Im trying (struggling) to implement a snapchat like error message display for my app (snapchat error messages slide down over the status bar somehow) in iOS7. I cannot for the life of me get my animation to work right. Here is my method that does the animation
- (void)animateHeaderViewWithText:(NSString *)text {
//add header views
[self.headerView addSubview:self.headerLabel];
[self.navigationController.view addSubview:self.headerView];
//Hide the Status Bar
statusBarHidden = TRUE;
[self setNeedsStatusBarAppearanceUpdate];
self.headerLabel.text = text;
[UIView animateWithDuration:.5 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.headerLabel.frame = CGRectMake(0, 0, 320, 20);
self.headerView.frame = CGRectMake(0, 0, 320, 20);
} completion:^(BOOL finished) {
[UIView animateWithDuration:.5 delay:5.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
//UnHide the Status Bar
statusBarHidden = FALSE;
[self setNeedsStatusBarAppearanceUpdate];
self.headerLabel.frame = CGRectMake(0, -20, 320, 20);
self.headerView.frame = CGRectMake(0, -20, 320, 20);
} completion:^(BOOL finished) {
[self.headerView removeFromSuperview];
[self.headerLabel removeFromSuperview];
}];
}];
}
Only the second half of the animation really works right, the message slides back up fine and the status bar appears underneath it. However, the first half of the animation, when the view slides down, the status bar disappears causing my navigation bar to move up, screwing up my animation. How can I get my navigation bar to stay where it is initially placed, even when the status bar is gone
This code worked in portrait, but would need to be modified to work properly in both orientations. It uses a separate UIWindow as the overlay, so there's no need to hide or unhide the status bar.
#interface ViewController ()
#property (strong,nonatomic) UIWindow *dropdown;
#property (strong,nonatomic) UILabel *label;
#property (strong,nonatomic) UIWindow *win;
#end
#implementation ViewController
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.dropdown = [[UIWindow alloc] initWithFrame:CGRectMake(0, -20, 320, 20)];
self.dropdown.backgroundColor = [UIColor redColor];
self.label = [[UILabel alloc] initWithFrame:self.dropdown.bounds];
self.label.textAlignment = NSTextAlignmentCenter;
self.label.font = [UIFont systemFontOfSize:12];
self.label.backgroundColor = [UIColor clearColor];
[self.dropdown addSubview:self.label];
self.dropdown.windowLevel = UIWindowLevelStatusBar;
[self.dropdown makeKeyAndVisible];
[self.dropdown resignKeyWindow];
}
- (IBAction)dropDown:(UIButton *)sender {
[self animateHeaderViewWithText:#"This is my test string"];
}
-(void)animateHeaderViewWithText:(NSString *) text {
self.label.text = text;
CGRect frame = self.dropdown.frame;
frame.origin.y = 0;
[UIView animateWithDuration:.6 delay:0 options:0 animations:^{
self.dropdown.frame = frame;
}completion:^(BOOL finished) {
;
}];
}
Related
I am new in iOS and I am facing a problem regarding to create slide out menu.
I searched and found the example but all are for storyboard and which I found in xib are called on AppDelegate Class.
I need to create a Slide out menu in xib which should be call after login.
Thanks in Advance!
The best example of side bar menu is SWRevealViewController. This library is easy to use and its easy to understand.
This below work for me well...try in your code.
_parentView is your custom slide out view and _rightView (UIButton )is used to dismiss these custom slide out view. you just initialize these two property
#property (strong,nonatomic) UIView *parentView;
#property (strong,nonatomic) UIButton *rightView;
-(void)slideView
{
if(![_parentView isDescendantOfView:app.navController.view])
{
[self showMenu];
}
else
{
[self hideMenu];
}
}
-(void)showMenu
{
int width=[[UIScreen mainScreen]bounds].size.width;
int height=[[UIScreen mainScreen]bounds].size.height;
_parentView =[[UIView alloc]initWithFrame:CGRectMake(0-(width-70), 0, width-70, self.navigationController.view.frame.size.height)];
[_parentView setBackgroundColor:[UIColor lightTextColor]];
[app.navController.view addSubview:_parentView];
_rightView=[[UIButton alloc]initWithFrame:CGRectMake(0,80, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-80)];
_rightView.alpha=0.7;
[_rightView addTarget:self action:#selector(hideMenu) forControlEvents:UIControlEventTouchUpInside];
if(_parentView.frame.origin.x <0)
{
[self performSelector:#selector(showSideMenu) withObject:nil afterDelay:0.2];
}
}
-(void)showSideMenu{
if(_parentView.frame.origin.x <0)
{
[UIView animateWithDuration:0.5 animations:^{
[UIView animateWithDuration:0.7 animations:^{
[self.view addSubview:_rightView];
_rightView.backgroundColor=[UIColor blackColor];
}];
CGRect frame = _parentView.frame;
frame.origin.x =0;
_parentView.frame = frame;
CGRect rightFrame=self.view.frame;
rightFrame.origin.x=_parentView.frame.size.width;
self.view.frame=rightFrame;
CGRect fram1=app.navController.navigationBar.frame;
fram1 .origin.x =_parentView.frame.size.width;
app.navController.navigationBar.frame =fram1 ;
} completion:^(BOOL finished) {
}];
}
}
-(void)hideMenu
{
if(_parentView.frame.origin.x == 0)
{
[UIView animateWithDuration:0.3 animations:^{
CGRect frame = _parentView.frame;
frame.origin.x=-_parentView.frame.size.width;
_parentView.frame = frame;
CGRect fram=self.view.frame;
fram .origin.x=0;
self.view.frame =fram ;
CGRect fram1=app.navController.navigationBar.frame;
fram1 .origin.x =0;
app.navController.navigationBar.frame =fram1 ;
} completion:^(BOOL finished) {
[_rightView removeFromSuperview];
[_parentView removeFromSuperview];
}];
}
}
Thank you...!!!
PUSH FROM NORMAL VIEW CONTROLLER TO SW VIEW CONTROLLER
UIStoryboard*Storyboard=[AppDelegate storyBoardType];
SidebarViewController *sidebarmemu =(SidebarViewController*)[Storyboard instantiateViewControllerWithIdentifier:#"SidebarController"];
tbTBC*tabbarController=(tbTBC*)[Storyboard instantiateViewControllerWithIdentifier:#"tbTBCId"];
SWRevealViewController *revealController;
UINavigationController *frontNavigationController;
UINavigationController *rearNavigationController;
frontNavigationController =[[UINavigationController alloc]initWithRootViewController:tabbarController];
rearNavigationController =[[UINavigationController alloc]initWithRootViewController:sidebarmemu];
revealController = [[SWRevealViewController alloc] initWithRearViewController:rearNavigationController frontViewController:frontNavigationController];
revealController.delegate = self;
self.swcontroller =revealController;
self.view.window.rootViewController =self.swcontroller;
WITH THE HELP OF THIS CODE YOU CAN GET BOTH TAB BAR AS WELL AS SIDE BAR
I am having one UIButton on navigation bar as right bar button item.
I want to show one view when I click on the UIButton,
and that view should appear animating from right to left and stops to perform some operations for user.
when user is done from his work on the view he will click on same button and view will hide animating from right to left.
I tried to load view normally I get succeed in it,
when I apply animation
view animates from right to left and disappears.
I am new to this animation scenario.
So can anyone please guide me to animate view and show hide action on same button.
Here is the code that I tried,
-(IBAction)showView :(id)sender
{
CGRect screen = [[UIScreen mainScreen]applicationFrame];
UIView *quizInfoViewObj;
quizInfoViewObj = [[UIView alloc]init];
quizInfoViewObj.frame = CGRectMake(70, 0, 250, 480);
quizInfoViewObj.backgroundColor = [UIColor orangeColor];
[UIView beginAnimations: nil context: NULL];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector: #selector(pushAnimationDidStop:finished:context:)];
quizInfoViewObj.center = self.view.center;
quizInfoViewObj.center = CGPointMake(self.view.center.x - CGRectGetWidth(self.view.frame), self.view.center.y);
[UIView commitAnimations];
[self.view addSubview:quizInfoViewObj];
}
here how I want...
This code might help you.
-(IBAction)showView :(id)sender
{
UIButton *button = (UIButton *)sender;
if ([button isSelected] == NO) {
CGRect screen = [[UIScreen mainScreen]applicationFrame];
// UIView *quizInfoViewObj; // use this line in .h file variables declaration
quizInfoViewObj = [[UIView alloc]init];
quizInfoViewObj.frame = CGRectMake(self.view.frame.width, 0, 250, 480);
quizInfoViewObj.backgroundColor = [UIColor orangeColor];
[self.view addSubview:quizInfoViewObj];
[UIView beginAnimations: nil context: NULL];
quizInfoViewObj.frame = CGRectMake(70, 0, 250, 480);
[UIView commitAnimations];
}
else {
[UIView beginAnimations: nil context: NULL];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector: #selector(pushAnimationDidStop:finished:context:)];
// In pushAnimationDidStop:finished:context method remove quizInfoViewObj from superview
quizInfoViewObj.frame = CGRectMake(self.view.frame.width, 0, 250, 480);
[UIView commitAnimations];
}
[button setSelected: ![button isSelected]];
}
I am pretty new in objective c so hopefully this all make sense.. I have declared UIView in .h file
#property (strong, nonatomic) UIView *menuViewone;
In .m file i declared UIView in viewdidload
menuViewone =[[UIView alloc ]initWithFrame:CGRectMake(-400, 0, 200, 568) ];
[menuViewone setBackgroundColor:[UIColor whiteColor]];
[self.view addSubview:menuViewone];
and set the view frame in Button method
- (IBAction)collectionmenutwo:(id)sender {
if (menuViewone.frame.origin.x >=0 ) {
[UIView animateKeyframesWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
menuViewone.frame=CGRectMake(-400, 100, 300, 568);
} completion:^(BOOL finished) {
}];
}
else
{
[UIView animateKeyframesWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
menuViewone.frame=CGRectMake(200, 100, 300, 568);
} completion:^(BOOL finished) {
}];
}}
Now i want to declare the buttons in this UIView ...How i can do that programmatically?
Just add buttons to the subview of that menuview of yours.
It would look something like this in the viewDidLoad of yours right after you declared your menuview.
UIButton *btn = [[UIButton] alloc] init];
btn.frame = CGRectMake(0,0,100,100);
//set other button properties here.
[menuViewone addSubview:btn];
For more specifics you can check this out:
How do I create a basic UIButton programmatically?
EDITED:
I had created a slide in menu for my view and it works as i wanted, this was the original guide that I used.
http://www.youtube.com/watch?v=79ZQDzzOHLk
My goal was to get this programmed once in a class and get it to work on any view controller that i decided to call it in.
Thanks to #harsh.prasad and some additional research I have managed to get this to work to a point where it works as I want apart apart from linking buttons on to it.
So to update this question in the hope it may help someone else.
This is what I did:
I created a UIView class and called it MenuOne.
MenuOne.h
#import <UIKit/UIKit.h>
#interface TFMenuOne : UIView {
// Pop Up Menu
IBOutlet UIScrollView *scrollView;
IBOutlet UIButton *openMenu;
int draw1;
IBOutlet UIButton *backButton;
}
// Pop Up Menu
- (IBAction)openMenu_clicked:(id)sender;
// Reset draw1 to 0
- (void) resetView: (id) sender;
#property (retain, nonatomic) IBOutlet UIScrollView *scrollView;
#end
MenuOne.m
#import "TFMenuOne.h"
#implementation TFMenuOne
#synthesize scrollView;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
draw1 = 0;
scrollView = [[UIScrollView alloc] init];
[scrollView setBackgroundColor:[UIColor whiteColor]];
[scrollView setFrame:CGRectMake(0, 315, 568, 5)];
[scrollView setContentSize:CGSizeMake(568, 5)];
backButton = [[UIButton alloc] init];
[backButton setBackgroundColor:[UIColor greenColor]];
backButton.frame = CGRectMake(224, 350, 120, 30);
openMenu = [[UIButton alloc] init];
[openMenu setBackgroundImage:[UIImage imageNamed:#"menu-button-#2.png"]
forState:UIControlStateNormal];
openMenu.adjustsImageWhenHighlighted = NO;
[openMenu addTarget:self
action:#selector(openMenu_clicked:)
forControlEvents:UIControlEventTouchUpInside];
openMenu.frame = CGRectMake(256, 269, 64, 46);
[self addSubview:scrollView];
[self addSubview:backButton];
[self addSubview:openMenu];
}
return self;
}
// Allow for touch even through transparent View class
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
for (UIView *view in self.subviews) {
if (!view.hidden && view.userInteractionEnabled && [view pointInside:[self convertPoint:point toView:view] withEvent:event])
return YES;
}
return NO;
}
- (void) resetView: (id) sender {
draw1 = 1;
[self openMenu_clicked:sender];
}
- (IBAction)openMenu_clicked:(id)sender {
if (draw1 == 0) {
draw1 = 1;
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
scrollView.frame = CGRectMake(0, 260, 568, 60);
} completion:^(BOOL finished) {
}];
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
openMenu.frame = CGRectMake(256, 214, 64, 46);
} completion:^(BOOL finished) {
}];
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
backButton.frame = CGRectMake(224, 275, 120, 30);
} completion:^(BOOL finished) {
}];
} else {
draw1 = 0;
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
scrollView.frame = CGRectMake(0, 315, 568, 5);
} completion:^(BOOL finished) {
}];
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
openMenu.frame = CGRectMake(256, 269, 64, 46);
} completion:^(BOOL finished) {
}];
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
backButton.frame = CGRectMake(224, 350, 120, 30);
} completion:^(BOOL finished) {
}];
}
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
After a lot of trial and error, in order to get this UIView class to appear on multiple ViewControllers I call the view like this in the m file of the view controller. The obstacles I ran in to was that the menu would open but when I left the view controller to go to another view controller the menu would be in the state it was in when i left, it wouldn't reset back to closed. The code below covered that thanks again to #harsh.prasad. I also managed to get the menu to animate in.
#interface TFMapViewController ()
{
TFMenuOne *menuView;
}
#end
#implementation TFMapViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
[menuView resetView:nil];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
menuView = [[TFMenuOne alloc] initWithFrame:CGRectMake(0, 51, 568, 320)];
[self.view addSubview:menuView];
}
- (void) viewDidAppear:(BOOL)animated
{
[UIView animateWithDuration:0.5 delay:0.5 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
menuView.frame = CGRectMake(0, 0, 568, 320);
} completion:^(BOOL finished) {
}];
}
- (void) viewDidDisappear:(BOOL)animated
{
[menuView resetView:nil];
[UIView animateWithDuration:0.0 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
menuView.frame = CGRectMake(0, 51, 568, 320);
} completion:^(BOOL finished) {
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// Allows for Exit button to work
- (IBAction)returned:(UIStoryboardSegue *)segue {
}
#end
I you want you can use tabsController if that kind of feature you want, otherwise create a class of your slide in menu view and then you can use it in all of your views as you like. No same piece of code is to be rewritten.
EDIT:
Suppose you have created a class CustomMenuView which basically creates your menu view. So now you can use this in every view controller you want to use it in in the following way:
CustomMenuView *menuView = [CustomMenuView alloc] initWithFrame:CGRectMake(0, 200, 320, 100);
menuView.<properties you want to pass> = <set properties here>;
[self.view addSubView:menuView];
This will set the view with the custom menu and then you can handle the actions in this menu.
1)Here is an old tutorial for creating menu - http://www.raywenderlich.com/32054/how-to-create-a-slide-out-navigation-like-facebook-and-path/projectlayout
2)A better way is to create Drawer menu With container views. You can read more about container views from WWDC videos.
3)Or if you are lazy to d it yourself, try this library http://cocoacontrols.com/platforms/ios/controls/jtrevealsidebar
P.S. No , you do not havev to repeat the code.
You can try this,
First make a view on the origin point x = 0 y = 480 (for iphone4) and then run this code.
CGRect theFrame = self.viewMenuShare.frame;
theFrame.origin = CGPointMake(0, 480);
self.viewMenuShare.frame = theFrame;
theFrame.origin = CGPointMake(0,480 - 187);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3f];
self.viewMenuShare.frame = theFrame;
[UIView commitAnimations];
I have a method that drops down a UIView. That works fine. How would I go about having it slide back up when the button is touched a second time?
I also need to deactivate it somehow so that it doesn't repeat the animation if it's already displayed.
- (void)slideDownTableView {
self.tableViewCities = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
self.tableViewCities.frame = CGRectMake(0,0,300,180);
self.tableViewCities.autoresizingMask = ( UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth );
self.tableViewCities.dataSource = self;
self.tableViewCities.delegate = self;
self.tableViewCities.backgroundColor = [UIColor whiteColor];
UIView *myview=[[UIView alloc] initWithFrame: CGRectMake(10, 0,300,180)];
myview.backgroundColor=[UIColor redColor];
[myview addSubview:self.tableViewCities];
[self.view addSubview:myview];
myview.frame = CGRectMake(10, 0,300,-180); // offscreen
[UIView animateWithDuration:0.5
animations:^{
myview.frame = CGRectMake(10, 0,300,180); // final location move
}];
}
iOS provides autoreverse property by which animation reverses automatically.
UIViewAnimationOptionAutoreverse will give you an effect as the animation reverses .
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionAutoreverse
animations:^{
// do whatever animation you want, e.g.,
someView.frame = someFrame1;
}
completion:NULL];
Using BeginFromCurrentState option worked for me.
if(!enabled){
[UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationTransitionCurlUp
animations:^{
myview.frame = CGRectMake(10, 0,300,180);
}
completion:nil];
enabled=YES;
}
else{
[UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationTransitionCurlUp
animations:^{
myview.frame = CGRectMake(10, 0,300,-180);
}
completion:nil];
enabled=NO;
}
With a simple BOOL to store the current state of the sliding UIView you can achieve this.
The initial state is not visible if I understand well? So initially the BOOL citiesVisible is set to N0, then the button's action check its value, and performs a different animation accordingly. Simple.
Finally, I also disable the button during the animation to prevent the user to trigger a second animation while a first one is already performing.
I rewrote a bit your code to follow some best practices, and improve readability/maintainability:
Setting up the views beforehand because the button's action responsibility shouldn't be to setup the views, but only to animate them.
Changed the signature of the target action, that's my personal style guide to state in the sender's name and the ControlEvent, it makes it more tidy when you have multiple buttons/actions ;). Also per Apple guidelines, methods receiving actions should have one "id" parameter, the sender.
Store the frames in variables (you could also have them as #define, that'd be even better I think), so you don't have to hard-code them twice, it reduces the risk of breaking the animation by having a view sliding to different positions...
Code update:
#interface ViewController ()
#property (nonatomic, strong) UIButton *showCitiesButton;
#property (nonatomic, strong) CGRect citiesInitialFrame;
#property (nonatomic, strong) CGRect citiesVisibleFrame;
#property (nonatomic, strong) UITableView *tableViewCities;
#property (nonatomic, strong) UIView *citiesContainer;
#property (nonatomic, strong) BOOL citiesVisible;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Setting up the cities view
self.citiesInitialFrame = CGRectMake(10, -180, 300, 180);
self.citiesVisibleFrame = CGRectMake(10, 0, 300, 180);
self.tableViewCities = [[UITableView alloc] init ...];
self.citiesContainer = [[UIView alloc] init ...];
// ...
self.citiesVisible = NO;
[self.showCitiesButton addTarget:self
action:#selector(showCitiesButtonDidTouchUpInside:)
forControlEvents:UIControlEventTouchUpInside];
}
- (void)showCitiesButtonDidTouchUpInside:(id)sender
{
[self.showCitiesButton setEnabled:NO];
if (self.citiesVisible)
{
// Cities view is visible, sliding it out of the screen
[UIView animateWithDuration:0.5
animations:^{
self.citiesContainer.frame = self.citiesInitialFrame;
} completion:^(BOOL finished) {
self.citiesVisible = NO;
[self.showCitiesButton setEnabled:YES];
}];
}
else
{
// Cities view is not visible, sliding it in
[UIView animateWithDuration:0.5
animations:^{
self.citiesContainer.frame = self.citiesVisibleFrame;
} completion:^(BOOL finished) {
self.citiesVisible = YES;
[self.showCitiesButton setEnabled:YES];
}];
}
}
#end
You can reverse UIView animation with this code:
if (isMarked) {
[UIView animateWithDuration:3
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:(void (^)(void)) ^{
self.transform=CGAffineTransformMakeScale(1.1, 1.1);
}
completion:nil];
} else {
[UIView animateWithDuration:3
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:(void (^)(void)) ^{
self.transform=CGAffineTransformIdentity;
}
completion:nil];
}