I have one viewcontroller. At top i am having one textfield.And also i am having one bar button item(add button) at navigation bar. In viewdidload initially my texfield will be hidden. when user press that bar button (add button) my textfield should be visible. now its working well.
Needer:
when user pressed (first time) my bar button (add button) should visible. then again when user press that same bar button item (add button) its should be again hidden.i did in visible .but i don't know again how to make its hidden...i am very beginner please help me out
i know that its should be done in if statement.but i don't know what condition should use ...help me this
Thanks in advance !
#import "ViewController.h"
#interface ViewController () {
UIBarButtonItem *addButton;
}
#end
#implementation ViewController
#synthesize tableView;
#synthesize textField;
- (void)viewDidLoad {
[super viewDidLoad];
addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addButtonPressed:)];
self.navigationItem.rightBarButtonItem = addButton;
txtField.hidden = YES;
}
- (void)addButtonPressed:(id)sender
{
txtField.hidden = NO;
}
#end
Ok for that you have to define a Bool variable, change the status of that Boolean variable on the click of your button like this
#import "ViewController.h"
#interface ViewController () {
Bool isShowingTF;
UIBarButtonItem *addButton;
}
#end
#implementation ViewController
#synthesize tableView;
#synthesize textField;
- (void)viewDidLoad {
[super viewDidLoad];
isShowingTF = NO;
addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addButtonPressed:)];
self.navigationItem.rightBarButtonItem = addButton;
txtField.hidden = YES;
}
- (void)addButtonPressed:(id)sender
{
if (isShowingTF) {
txtField.hidden = YES;
} else {
txtField.hidden = NO;
}
isShowingTF = ! isShowingTF;
}
#end
you can do this in many ways just like set BOOL for yes:No condition, else identify with Tags else use some common NSString like
#interface ViewController () {
UIBarButtonItem *addButton;
NSString *GettouchStr;
}
- (void)viewDidLoad {
[super viewDidLoad];
addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addButtonPressed:)];
self.navigationItem.rightBarButtonItem = addButton;
txtField.hidden = YES;
GettouchStr=#"hidden";
}
- (void)addButtonPressed:(id)sender
{
if ([GettouchStr isEqualToString:#"hidden"])
{
[UIView animateWithDuration:0.3 animations:^{
txtField.alpha = 1;
} completion: ^(BOOL finished) {
txtField.hidden = NO;
GettouchStr=#"UNhidden";
}];
}
else
{
[UIView animateWithDuration:0.3 animations:^{
txtField.alpha = 0;
} completion: ^(BOOL finished) {
txtField.hidden = YES;
GettouchStr=#"hidden";
}];
}
}
Choice - 2 for additional animation
- (void)addButtonPressed:(id)sender
{
if ([GettouchStr isEqualToString:#"hidden"])
{
txtField.alpha = 1;
[UIView animateWithDuration:2.f delay:0.f options:UIViewAnimationOptionCurveEaseIn animations:^{
txtField.alpha = 0;
} completion:^(BOOL finished) {
[UIView animateWithDuration:2.f delay:0.f options:UIViewAnimationOptionCurveEaseInOut animations:^{
txtField.alpha = 1;
txtField.hidden = NO;
GettouchStr=#"UNhidden";
} completion:nil];
}];
}
else
{
txtField.alpha = 0;
[UIView animateWithDuration:2.f delay:0.f options:UIViewAnimationOptionCurveEaseIn animations:^{
txtField.alpha = 1;
} completion:^(BOOL finished) {
[UIView animateWithDuration:2.f delay:0.f options:UIViewAnimationOptionCurveEaseInOut animations:^{
txtField.alpha = 0;
txtField.hidden = YES;
GettouchStr=#"hidden";
} completion:nil];
}];
}
}
Choice-3
see this link may be help with you
In Swift 4, If you have only one bar button item in the right side you can use this one,
self.navigationItem.rightBarButtonItem = nil; //To Hide
self.navigationItem.rightBarButtonItem = barButtonItem //To show
Suppose if you have multiple bar button in the right side, for example suppose you have two bar button items(search button and filter button) in the right side of your navigation item. And now you have to hide only search button, you can use like,
self.navigationItem.rightBarButtonItems = [filterItem]
Now what happening is, you can completely hide the search button from the navigation item and the filter item comes in the place of search item
Then if you want to show the hided bar button,
self.navigationItem.rightBarButtonItems = [searchItem, filterItem]
Now in the navigationItem searchItem comes as the first item, filterItem comes as the second item.
Related
I'm having a problem with reading taps on navigation bar (I need to open dropdown menu by tapping on title field, just like in telegram and etc. but not in swift)
I know that basically its unreadable, and already've tried with taprecognizer, but it didn't work for me any good.
Now my menu opens with rightbarbutton - that's ugly.
How can I deal with it?
Now string that drops menu (placed in viewDidLoad) looks like:
navbar = [[UIBarButtonItem alloc]initWithTitle:#"navbar" style:UIBarButtonItemStylePlain target:self action:#selector(navigationTitleTapGestureAction:)];
and a part that declares button:
NSArray *buttons = #[navbar <<...a few more buttons...>>];
self.navigationItem.rightBarButtonItems = buttons;
EDIT: additional code from the comments:
- (IBAction)navigationTitleTapGestureAction:(id)sender {
automaticDisappearanceCanceled_ = YES;
if (menuToolbarVisible_) {
[self hideMenuAnimated:YES];
}
else {
[self showMenuAnimated:YES];
}
}
- (void)showMenuAnimated:(BOOL)animated {
[self.view layoutIfNeeded];
self.toolbarTopLayoutConstraint.constant = 0.f;
self.menuToolbar.hidden = NO;
[UIView animateWithDuration:animated ? ToolbarMenuAnimationDuration : 0.f animations:^{
[self.view layoutIfNeeded];
} completion: ^(BOOL finished) {
}];
menuToolbarVisible_ = YES;
}
- (void)hideMenuAnimated:(BOOL)animated {
[self.view layoutIfNeeded];
self.toolbarTopLayoutConstraint.constant = -ToolbarMenuHeight;
[UIView animateWithDuration:animated ? ToolbarMenuAnimationDuration : 0.f animations: ^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self.menuToolbar.hidden = YES;
}];
menuToolbarVisible_ = NO;
}
As far is I know you just want to get taps on the text on the center of navigation bar you can do this by adding a UIButton in the titleView like this :-
UIButton *centerButton=[[UIButton alloc]initWithFrame:CGRectMake(0, 0, 44.0, 44.0)];
[centerButton setTitle:#"Center" forState:UIControlStateNormal];
[centerButton addTarget:self action:#selector(action) forControlEvents:UIControlEventTouchDown];
self.navigationItem.titleView=centerButton;
I have this problem, i have set in the Storyboard 2 UIButton and after touching one of them they must move, so i implemented this using animation, and works fine. But after the completion of the animation i'm performing a modal segue, the problem is that while modal segue is starting, raising the new UIView from the bottom, the 2 UIButton return to their previous place, where i set them in the Storyboard, and it's orribile to see. How could i solve this?
Here's the code i'm using
#property (strong, nonatomic) IBOutlet UIButton *maleBtn;
#property (strong, nonatomic) IBOutlet UIButton *femaleBtn;
- (void)viewDidLoad
{
[super viewDidLoad];
[_maleBtn addTarget:self
action:#selector(chooseGender:)
forControlEvents:UIControlEventTouchUpInside];
[_femaleBtn addTarget:self
action:#selector(chooseGender:)
forControlEvents:UIControlEventTouchUpInside];
}
- (IBAction)chooseGender:(id)sender
{
CGRect maleFrame;
CGRect femaleFrame;
if (sender == _maleBtn) {
maleFrame = self.maleBtn.frame;
maleFrame.origin.x = (self.view.bounds.size.width/2) - 15;
femaleFrame = self.femaleBtn.frame;
femaleFrame.origin.x = self.view.bounds.size.height;
}
else {
maleFrame = self.maleBtn.frame;
maleFrame.origin.x = -self.view.bounds.size.height;
femaleFrame = self.femaleBtn.frame;
femaleFrame.origin.x = (self.view.bounds.size.width/2) - 15;
}
[UIView animateWithDuration:0.5
delay:0.5
options:UIViewAnimationCurveEaseOut
animations:^{
_maleBtn.frame = maleFrame;
_femaleBtn.frame = femaleFrame;
}
completion:^(BOOL finished){
if(sender == _maleBtn)
[self performSegueWithIdentifier:#"toMale" sender:self];
else
[self performSegueWithIdentifier:#"toFemale" sender:self];
}];
}
At the top you make a bool or add a property in your .h if you like. But I would just use a local variable for this.
BOOL didAnimate;
In viewDidLoad you set it
- (void)viewDidLoad
{
[super viewDidLoad];
//Set the bool value here to no;
didAnimate = NO;
[_maleBtn addTarget:self
action:#selector(chooseGender:)
forControlEvents:UIControlEventTouchUpInside];
[_femaleBtn addTarget:self
action:#selector(chooseGender:)
forControlEvents:UIControlEventTouchUpInside];
}
Use it here, and I also took the liberty to rewrite your code a bit.
- (IBAction)chooseGender:(id)sender
{
CGRect maleFrame;
CGRect femaleFrame;
if (sender == _maleBtn) {
maleFrame = self.maleBtn.frame;
maleFrame.origin.x = (self.view.bounds.size.width/2) - 15;
femaleFrame = self.femaleBtn.frame;
femaleFrame.origin.x = self.view.bounds.size.height;
}
else {
maleFrame = self.maleBtn.frame;
maleFrame.origin.x = -self.view.bounds.size.height;
femaleFrame = self.femaleBtn.frame;
femaleFrame.origin.x = (self.view.bounds.size.width/2) - 15;
}
[UIView animateWithDuration:0.5
delay:0.5
options:UIViewAnimationCurveEaseOut
animations:^{
_maleBtn.frame = maleFrame;
_femaleBtn.frame = femaleFrame;
}
completion:^(BOOL finished){
didAnimate = YES;
}];
if(sender == _maleBtn && didAnimate){
[self performSegueWithIdentifier:#"toMale" sender:self];
}
else if((sender == _femaleBtn && didAnimate)){
[self performSegueWithIdentifier:#"toFemale" sender:self];
}
else{
NSLog(#"failure to transition");
}
}
I have not tested this and there might be spelling errors and such. So copy/paste might not work.
Trying to get to grips with Xcode and seem to be making some progress over the last few weeks.
Does anyone know a way that a custom button can do a different set of animations on a second click.
So let say I have a custom button and its of Mario, when i click it he runs from the middle of the screen and out of the right hand side of the screen and then runs back in to the middle from the left of the screen, he also makes noise.
I have achieved this using this code:
- (IBAction)marioRunning_clicked:(id)sender
{
[UIView animateWithDuration:1.50 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
marioRunning.center = CGPointMake(350.5, 456.0);
} completion:^(BOOL finished) {
if (finished) {
[UIView animateWithDuration:0.00 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
marioRunning.center = CGPointMake(-30.5, 456.0);
} completion:^(BOOL finished) {
if (finished) {
[UIView animateWithDuration:1.50 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
marioRunning.center = CGPointMake(160.0, 456.0);
} completion:^(BOOL finished) {
if(finished) // NSLog ( #"Finished !!!!!" );
marioRunning.center = CGPointMake(160.0, 456.0);
}];
}
}];
}
}];
marioRunning.imageView.animationImages = [NSArray arrayWithObjects:[UIImage imageNamed:#"mario-running2"],[UIImage imageNamed:#"mario-running3"],nil];
marioRunning.imageView.animationDuration = 0.15;
marioRunning.imageView.animationRepeatCount = 19;
[marioRunning.imageView startAnimating];
}
How could I make him do a second set of animations on the next click? For example instead of running from left to right, if i tap him the second time he will Jump up and down?
Use the selected state of the button to decide which animation to do
-(void)buttonClicked:(UIButton*)button
{
if(button.selected)
{
[self doAnimation1];
}
else
{
[self doAnimation2];
}
button.selected = !button.selected;
}
This might be overkill, but here's a cool way to do what you want:
Make a subclass of UIButton, and let's call it DDDMarioButton:
typedef void (^DDDAnimationBlock)(UIButton *button);
#interface DDDMarioButton : UIButton
- (void)addAnimationBlockToQueue:(DDDAnimationBlock)block;
#end
Then in DDDMarioButton.m:
#interface DDDMarioButton ()
#property (nonatomic, strong) NSMutableArray *animationQueue;
#end
#implementation DDDMarioButton
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
- (void)buttonPressed:(id)button
{
DDDAnimationBlock block = self.animationQueue[0];
block(self);
[self.animationQueue removeObjectAtIndex:0];
}
- (void)addAnimationBlockToQueue:(DDDAnimationBlock)block
{
if(!self.animationQueue)
{
self.animationQueue = [NSMutableArray new];
}
[self.animationQueue addObject:block];
}
#end
and then wherever you create your buttons, you add each step one by one:
DDDMarioButton *button = [[DDDMarioButton alloc] initWithFrame:CGRectZero];
[button addAnimationBlockToQueue:^(UIButton *button) {
// perform some animation
}];
[button addAnimationBlockToQueue:^(UIButton *button) {
// perform another animation
}];
And that should do it. I haven't tested this, you'll probably need some configuration, but that's pretty much the idea.
I have a problem with an app that won't set frames outside -init and -viewWillLayoutSubviews methods. What should happen when one taps the editButton is an animation that will hide the editor view. Nonetheless, nothing happens as I test it. The problem doesn't come from the animation method since the -setFrame method as it - not included in the block - doesn't work neither.
Here is the code :
-(id)init {
if (self = [super init]) {
editButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(editButtonTapped)];
doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(doneButtonTapped)];
editor = [[UIView alloc] init];
[editor setBackgroundColor:[UIColor yellowColor]];
editor.clipsToBounds = YES;
editorIsOpen = YES;
portraitRegularModeEditorRect = CGRectMake(15, 59, 738, 100);
portraitClosedEditorEditorRect = CGRectMake(15, 59, 738, 0);
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[[self view] addSubview:editor];
[[self view] setBackgroundColor:[UIColor blueColor]];
}
-(void)viewDidAppear:(BOOL)animated {
[self setForRegularMode];
}
-(void)viewWillLayoutSubviews {
UIInterfaceOrientation io = [[UIApplication sharedApplication] statusBarOrientation];
if (io == UIInterfaceOrientationPortrait || io == UIInterfaceOrientationPortraitUpsideDown) {
//portrait
[editor setFrame:portraitRegularModeEditorRect];
} else {
//landscape
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(void)editButtonTapped {
[self setForScenarioLinesEditingMode];
}
-(void)doneButtonTapped {
[self setForRegularMode];
}
-(void)setForRegularMode {
editingMode = CPRegularMode;
if (!editorIsOpen) {
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationCurveEaseOut animations:^(void){
[editor setFrame:portraitRegularModeEditorRect];
} completion:^(BOOL finished) {
editorIsOpen = YES;
}];
}
[[self navigationItem] setRightBarButtonItems:[[NSArray alloc] initWithObjects:editButton,nil]];
}
-(void)setForScenarioLinesEditingMode {
editingMode = CPScenarioLinesEditingMode;
if (editorIsOpen) {
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationCurveEaseOut animations:^(void){
[editor setFrame:portraitClosedEditorEditorRect];
} completion:^(BOOL finished) {
editorIsOpen = NO;
}];
}
[[self navigationItem] setRightBarButtonItems:[[NSArray alloc] initWithObjects:doneButton,nil]];
}
If anyone can help, thanks in advance ;)
I think that the problem in your case is the fact that in -(void)viewWillLayoutSubviews method you set, lets say the default frame of your view, if you try to change the frame in other methods after the setFrame is called on your view, the -(void)viewWillLayoutSubviews will also be called and the frame of the view will be the default one. Try to remove the setFrame from your -(void)viewWillLayoutSubviews.
Is your view controller set up in storyboards, and are you using Autolayout (which is on by default?) If so, setFrame won't work and you need to edit constraints after creating outlets to them from the storyboard.
Alternatively, you can turn off Autolayout in your storyboard, as shown here.
I have a requirement to show a status bar at certain times at the bottom of my application. I can easily put this at the bottom of my application's main view, but whenever I push a view controller on top of this (either modally or not) it hides this status bar.
Is there any way I can add a status bar like this, and have it be outside the bounds of my application itself? Ideally I'd like this to work like the call-in-progress status bar on the iPhone - when this bar appears, the app is pushed down, and a call to [[UIScreen mainScreen] applicationFrame] returns the correct size (i.e. it accounts for the presence of this status bar when calculating the height available for the app).
I wanted to do this, too, so I tried View Controller Containment. I'm still trying it out, so I'm not willing to give this a ringing endorsement, but it might be something you'd want to try playing around with yourself if you're in iOS5. But it appears to give you a status bar that will appear or disappear from the bottom of the screen.
This is a view controller that will open another view controller, but if there is status text to show, it pops up from the bottom of the screen and stays there until you get rid of it. I've only done a little testing so far, but it looks like this handles pushViewController/popViewController, but maybe not modal views.
My header looks like:
// StatusBarViewController.h
//
// Created by Robert Ryan on 7/8/12.
#import <UIKit/UIKit.h>
#interface StatusBarViewController : UIViewController
#property (strong, nonatomic) UIViewController *appController;
- (void)setStatus:(NSString *)text;
#end
My implementation file (this is ARC) looks like:
// StatusBarViewController.m
//
// Created by Robert Ryan on 7/8/12.
#import "StatusBarViewController.h"
#interface StatusBarViewController ()
{
BOOL _statusHidden;
UIView *_appView;
UILabel *_statusLabel;
}
#end
#implementation StatusBarViewController
#synthesize appController = _appController;
- (void)dealloc
{
_appView = nil;
_statusLabel = nil;
[self setAppController:nil]; // usually I don't like setters in dealloc, but this does some special stuff
}
- (void)createControlsWithStatusHidden
{
// create default app view that takes up whole screen
CGRect frame = self.view.frame;
frame.origin = CGPointMake(0.0, 0.0);
_appView = [[UIView alloc] initWithFrame:frame];
_appView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_appView.clipsToBounds = YES;
[self.view addSubview:_appView];
// create status label that is just off screen below the app view
_statusLabel = [[UILabel alloc] init];
_statusLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size:12.0];
_statusLabel.backgroundColor = [UIColor darkGrayColor];
_statusLabel.textColor = [UIColor whiteColor];
CGSize size = [#"Hey!" sizeWithFont:_statusLabel.font]; // test size of box with random text
_statusLabel.frame = CGRectMake(0.0, frame.size.height, frame.size.width, size.height);
_statusLabel.textAlignment = UITextAlignmentCenter;
_statusLabel.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:_statusLabel];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self createControlsWithStatusHidden];
_statusHidden = YES;
// I'm instantiating from storyboard. If you're using NIBs, just create your controller controller using initWithNib and then set our appController accordingly.
self.appController = [self.storyboard instantiateViewControllerWithIdentifier:#"MainNavigator"];
}
- (void)setAppController:(UIViewController *)controller
{
if (controller)
{
controller.view.frame = CGRectMake(0.0, 0.0, _appView.frame.size.width, _appView.frame.size.height);
[self addChildViewController:controller];
[controller didMoveToParentViewController:self];
if (self.appController)
{
// if we have both a new controller and and old one, then let's transition, cleaning up the old one upon completion
[self transitionFromViewController:self.appController
toViewController:controller
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionCurveEaseInOut
animations:nil
completion:^(BOOL finished){
if (self.appController)
{
[self.appController willMoveToParentViewController:nil];
[self.appController removeFromParentViewController];
}
}];
}
else
{
// if we have no previous controller (i.e. this is our first rodeo), then just add it to the view
[_appView addSubview:controller.view];
}
}
else
{
// no new controller, so we're just removing any old on if it was there
if (self.appController)
{
// if there was an old controller, remove it's view, and remove it from the view controller hierarchy
[self.appController.view removeFromSuperview];
[self.appController willMoveToParentViewController:nil];
[self.appController removeFromParentViewController];
}
}
_appController = controller;
}
- (void)hideStatusWithCompletion:(void (^)(BOOL finished))completion
{
[UIView animateWithDuration:0.25
animations:^{
CGRect labelFrame = _statusLabel.frame;
labelFrame.origin.y += labelFrame.size.height;
_statusLabel.frame = labelFrame;
CGRect appFrame = _appView.frame;
appFrame.size.height += labelFrame.size.height;
_appView.frame = appFrame;
}
completion:completion];
}
- (void)unhideStatusWithCompletion:(void (^)(BOOL finished))completion
{
[UIView animateWithDuration:0.25
animations:^{
CGRect labelFrame = _statusLabel.frame;
labelFrame.origin.y -= labelFrame.size.height;
_statusLabel.frame = labelFrame;
CGRect appFrame = _appView.frame;
appFrame.size.height -= labelFrame.size.height;
_appView.frame = appFrame;
}
completion:completion];
}
- (void)setStatus:(NSString *)text
{
BOOL hasText = (text && [text length] > 0);
if (hasText)
{
if (!_statusHidden)
{
// if we have text, but status is already shown, then hide it and unhide it with new value
[self hideStatusWithCompletion:^(BOOL finished){
_statusLabel.text = text;
[self unhideStatusWithCompletion:nil];
}];
}
else
{
// if we have text, but no status is currently shown, then just unhide it
_statusLabel.text = text;
[self unhideStatusWithCompletion:nil];
}
_statusHidden = NO;
}
else
{
if (!_statusHidden)
{
// if we don't have text, but status bar is shown, then just hide it
[self hideStatusWithCompletion:^(BOOL finished){
_statusLabel.text = text;
}];
_statusHidden = YES;
}
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
And then, any view controller that wants to update the status message would use a method kind of like:
- (void)setStatus:(NSString *)text
{
UIViewController *controller = [UIApplication sharedApplication].delegate.window.rootViewController;
if ([controller isKindOfClass:[StatusBarViewController class]])
{
[(StatusBarViewController *)controller setStatus:text];
}
}