Button in iPhoto that reveal another sliding toolbar - ios

How can I develop a toolbar like this one, with a button that when it's pressed reveals another toolbar (sliding on top of the current one)? This is a screenshot from the iPhoto application from Apple.
http://i.stack.imgur.com/dKYZq.png

I got this to work using the following (Disclaimer: THIS MAY VIOLATE THE HIG!):
I added a new, basic UIViewController.
I added a UIToolbar to the view of the UIViewController. I connected this UIToolbar to a property in my UIViewController named "BaseToolbar".
To "BaseToolbar", I added a button. I connected this button to an IBAction called "AddPressed:" in my UIViewController.
I added a UIToolbar to the UIViewController's xib, BUT NOT ON THE UIViewController's view. I just added it onto the design surface. I connected this UIToolbar to a property in my UIViewController named "SecondToolbar".
To "SecondToolbar", I added a button. I connected this button to an IBAction called "TrashPressed:" in my UIViewController.
I used the following code:
- (IBAction)AddPressed:(id)sender {
CGRect secondCurrRect = [[self SecondToolbar] frame];
[[self SecondToolbar] setFrame:CGRectMake(0, -1 * secondCurrRect.size.height, secondCurrRect.size.width, secondCurrRect.size.height)];
[[self view] addSubview:[self SecondToolbar]];
[[self view] bringSubviewToFront:[self SecondToolbar]];
[UIView animateWithDuration:1.0
animations:^(void){
[[self SecondToolbar] setFrame:CGRectMake(0, 0, secondCurrRect.size.width, secondCurrRect.size.height)];
}];
}
- (IBAction)TrashPressed:(id)sender {
CGRect secondCurrRect = [[self SecondToolbar] frame];
[UIView animateWithDuration:1.0
animations:^(void){
[[self SecondToolbar] setFrame:CGRectMake(0, -1 * secondCurrRect.size.height, secondCurrRect.size.width, secondCurrRect.size.height)];
}
completion:^(BOOL finished) {
[[self SecondToolbar] removeFromSuperview];
}];
}
Using that code, the new UIToolbar slides on/off ON TOP OF the "base" UIToolbar.
Edit/Update
Let's try a different tactic.
(This assumes you're adding the UIToolbar objects to your xib at design time)
Add Toolbar #1 (the one that is always on-screen) to the top of the view and position it like you want.
Add Toolbar #2 (the one that slides on/of) underneath Toolbar #1 and build it out with the buttons you want.
Put the following line of code into your -(void)viewDidLoad method (this will move the second toolbar off-screen):
[[self Toolbar2] setFrame:
CGRectMake(0, // origin.x
-[[self Toolbar2] frame].size.height, // origin.y
[[self Toolbar2] frame].size.width, // size.width (remains the same)
[[self Toolbar2] frame].size.height) // size.height (remains the same)
];
Then, use the code from above, but skip the calls to addSubview: and removeFromSuperview.
Does that make sense now?

Related

How to Remove and Adding Constraints when we change simulator orientation(like portrait to landscape) in ios

Hi i am very new for Auto-layouts and in my project i have added Two UIViews programmatically using Auto-layouts and i have added two UIButton which are Next and Back button and when i click Next button i push MyFirst UIView to second UIView using UIView animations and when i click Back button i push back from Second UIView to First UIView ok Everything is all right based on my code
But here my main problem is when i change First UIView orientation in simulator at portrait to landscape then Second UIView overlapped on my First UIView, And i know that it is must be Constrains issue i mean i have to remove and adding Constraints each time when we change Orientation for this i have tried below code but that's not working please help me and for this i have tried since long time but no one saying right answers using constrains
when we run program at portrait mode screen is coming like image1 and when i change land scape mode second UIview overlapped on my first UIview like below second image that's my main problem
my code:-
#import "SubViewController.h"
#interface SubViewController (){
UIButton * GoNext;
UIButton * GoBack;
NSArray * FHorizental;
NSArray * FVertical;
NSArray * SHorizental;
NSArray * SVertical;
}
#end
#implementation SubViewController
#synthesize MyFisrtView,MySecondView;
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"How are you");
[self callAutolayouts];
MyFisrtView.hidden = NO;
MySecondView.hidden = YES;
}
-(void)callAutolayouts{
NSLog(#"Hi");
MyFisrtView = [[UIView alloc] init];
MyFisrtView.backgroundColor = [UIColor orangeColor];
MyFisrtView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:MyFisrtView];
MySecondView = [[UIView alloc] init];
MySecondView.backgroundColor = [UIColor lightGrayColor];
MySecondView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:MySecondView];
//Applying autolayouts for MyFirstView and MySecondView
NSDictionary * HeaderDictionary = NSDictionaryOfVariableBindings(MyFisrtView,MySecondView);
//Appliying Autolayouts for FirstView
FHorizental =[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-0-[MyFisrtView]-0-|"]
options:0
metrics:nil
views:HeaderDictionary];
FVertical = [NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:|-0-[MyFisrtView]-0-|"]
options:0
metrics:nil
views:HeaderDictionary];
[self.view addConstraints:FHorizental];
[self.view addConstraints:FVertical];
//Appliying Autolayouts for SEcondView
SHorizental =[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-0-[MySecondView]-0-|"]
options:0
metrics:nil
views:HeaderDictionary];
SVertical = [NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:|-0-[MySecondView]-0-|"]
options:0
metrics:nil
views:HeaderDictionary];
[self.view addConstraints:SHorizental];
[self.view addConstraints:SVertical];
GoNext = [UIButton buttonWithType: UIButtonTypeRoundedRect];
GoNext.frame = CGRectMake(50, 50, 100, 18);
[GoNext setTitle:#"Next" forState:UIControlStateNormal];
[GoNext addTarget:self action:#selector(GoNext:) forControlEvents:UIControlEventTouchUpInside];
GoNext.backgroundColor = [UIColor lightGrayColor];
[MyFisrtView addSubview:GoNext];
GoBack = [UIButton buttonWithType: UIButtonTypeRoundedRect];
GoBack.frame = CGRectMake(50, 50, 100, 18);
[GoBack setTitle:#"Back" forState:UIControlStateNormal];
[GoBack addTarget:self action:#selector(GoBack:) forControlEvents:UIControlEventTouchUpInside];
GoBack.backgroundColor = [UIColor orangeColor];
[MySecondView addSubview:GoBack];
}
-(void)GoNext:(id)sender{
MySecondView.hidden = NO;
MySecondView.frame=CGRectMake(248, 0, self.view.frame.size.width, self.view.frame.size.height); // starting visible position
[UIView animateWithDuration:0.5f
delay:0.0f
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
[self.view removeConstraints:self.view.constraints];
[self callAutolayouts];
[self.view setNeedsLayout];
[MySecondView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; // final visible position
}
completion:nil];
}
-(void)GoBack:(id)sender{
MySecondView.frame=CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); // starting visible position
[UIView animateWithDuration:0.5f
delay:0.0f
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
[self.view removeConstraints:self.view.constraints];
[self callAutolayouts];
[self.view setNeedsLayout];
[MySecondView setFrame:CGRectMake(MyFisrtView.frame.size.width, 0, self.view.frame.size.width, self.view.frame.size.height)]; // final visible position
}
completion:nil];
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
if(toInterfaceOrientation == UIInterfaceOrientationPortrait){
NSLog(#"portrait");
[self.view removeConstraints:self.view.constraints];
[self callAutolayouts];
[self.view setNeedsLayout];
}
else if(toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
NSLog(#"LandscapeRight");
[self.view removeConstraints:self.view.constraints];
[self callAutolayouts];
[self.view setNeedsLayout];
}
else if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
NSLog(#"LandscapeLeft");
[self.view removeConstraints:self.view.constraints];
[self callAutolayouts];
[self.view setNeedsLayout];
}
}
#end
image1:-
image2:-
First you have to remove the constraints and then add agin as you did in your question.
You could follow a tutorial on auto layout so that you can get a little know how about it. Here's a link.
Another option is the use of springs and struts.
I hope that answers your question.
Based on your comments below I'm updating my answer but leaving the original below as it may help you or others down the road.
Your issue isn't really Auto Layout then, your real issue is an architecture design issue. Every view that comes onto screen should have a different view controller running it. It sounds like you are drawing one view that is double the width of the device, one half (I'm guessing the left half) has the next button on it while the other half includes the back button. As soon as your app runs on a screen with a different size this will break unless you are checking for the screen size. Even then it breaks (as you have seen) when the device is rotated.
You need to make two different view controller subclasses, one to run the 'Next' view and one for the 'Back' view then you will never have the both views onscreen because the device got rotated.
The really hard way to get the effect you want is to do it all in code like you've tried thus far. If there is some strange reason that you just have to code it all instead of using the storyboard that was included when you started the project you will need to look at the animation methods of UIView (specifically look at the documentation for + (void)transitionFromView: toView: duration: options: completion: if you want something like a flip or page curl). If you want to slide between the two views you should really look into UINavigationController as it does all that for you. The other option would be when the Next button gets pressed create the second view controller, who will create the second view, and set it's frame to be off screen. Then animate the frame of the view to the onscreen position. Back would have to animate the frame of the Back view off the screen again and remove the view. It will take a lot of code to get all of this working which will mean reading a lot of documentation, I highly recommend using a storyboard to take care of this issue.
If you want the easy way use the storyboard and drag out a second view controller. Add a button to each scene in whatever location you want them to be in and set the text as desired. Control drag from the Next button to the second scene and select the kind of transition you would like. Add the following code to the view controller running the view with the Next button
#IBAction func exitToViewController (sender: UIStoryboardSegue){ }
Control drag from the Back button to the Exit icon (top of the scene all the way to the right, it's red with a white box and an arrow point to the right) select exitToViewController. Select one of the scenes and select Editor -> Resolve Auto Layout Issues -> Reset To Suggested Constraints (the second one under all views). It takes five minutes to do and works wonderfully.
If you need help with any of the tasks mentioned in the Storyboard route consider finding a beginner level tutorial on Xcode (there is a pretty good overview class on Coursera.org that isn't terribly long but covers many of the basics called,Foundations of Objective-C App Development and it's free if you don't care about a verified certificate.
Original Answer
Is there a reason the UI has to be built programmatically?
Building it in IB will make your life much easier as you can build the base version of the UI and then create overrides for specific size classes (look at the bottom of IB where it says w Any h Any and change the selection to be compact height). Once in the compact height make any modifications you need to the constraints and visibility of UI elements. The system should take care of things from there (you might have to manually hide and show the correct UI elements as need for the orientations).
When building in IB one of the Assistant editors is preview. You can select various devices and change the orientation between landscape and portrait, this will allow you to see in real time what your view is going to do when run for real rather than making a change in code and then running the app again. You can add one of each device if you want and they can all have their own orientation allowing you to see the UI in landscape and portrait at the same time.
If it does has to be done in code and you have to actually remove the unused elements from the UI rather than hiding them you will have to set all the constraints for the landscape orientation every time the device rotates to that orientation, the same is true for the portrait orientation. The best thing to do is to make the constraint changes in an animation block rather than manually updating the frames, this will cause the views to animate into place (you can do any alpha adjustments at the same time to fade elements in and out).

Custom UIActivityViewController-like view that slides up and down

Is there a way to subclass or customize UIActivityViewController to create a sort of custom view? For example, see the image below from the app Overcast. I want to create a view similar to that, where if you tap a button, the view pops up and when you tap outside of the view, it slides back down.
Why not use an UIView ? Set it's initial frame's y value to -self.customView.frame.size.height and animate it's frame to the normal position using [UIView animateWithDuration]
-(void)showCustomView{
[self.customview setFrame:CGRectMake(0, -self.customView.frame.size.height, self.view.bounds.size.height+self.customView.frame.size.width, self.customView.frame.size.height)];
[UIView animateWithDuration:0.25 animations:^{
[self.customView setFrame:CGRectMake(0, -self.view.frame.size.height, self.view.bounds.size.height-self.customView.frame.size.width, self.customView.frame.size.height)];
}];
}
-(void)hideCustomView{
[UIView animateWithDuration:0.25 animations:^{
[self.customView setFrame:CGRectMake(0, -self.customView.frame.size.height, self.customView.bounds.size.height+self.customView.frame.size.width, self.customView.frame.size.height)];
}];
}
Add an UITapGestureRecognizer and call hideCustomView when tapped outside the customView

Fade UIBarButtonItem When Swapped

When I change my UIBarButtonItems they change abruptly, unlike the default which gives a nice but speedy fade animation. You can see this when segueing between view controllers, for instance, the back button will fade in and out. How can I simulate the same effect?
Update - Based on this answer - https://stackoverflow.com/a/10939684/2649021
It looks like you would have to do something like this to make the button itself fade out.
[self.navigationItem setRightBarButtonItem:nil animated:YES];
And do something like this to make it fade in
[self.navigationItem setRightBarButtonItem:myButton animated:YES];
Otherwise if you want more control over animation properties you would have to create a custom view I believe.
EDIT: I just confirmed that you can fade a UIBarButtonItem custom view using this.
As a test I created a simple project and dropped a UIBarButtonItem onto the navigation bar. I created an outlet to the view controller. In viewDidLoad on the view controller I setup a custom view
-(void)viewDidLoad{
[super viewDidLoad];
UILabel *lbl = [[UILabel alloc]initWithFrame:CGRectMake(0,0,40,40)];
lbl.text = #"test";
UIView *customView = [[UIView alloc]initWithFrame:CGRectMake(0,0,40,40)];
[customView addSubview:lbl];
self.barButtonItem.customView = customView;
}
As a test in viewDidAppear I animated it
-(void)viewDidAppear:(BOOL)animated
{
[UIView animateWithDuration:3.0
delay:3.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.barButtonItem.customView.alpha = 0;
}
completion:^(BOOL finished) {
NSLog(#"animation complete");
}];
EDIT: Here's a link to Apples Documentation for a full explanation of UIView animations.
https://developer.apple.com/library/ios/documentation/windowsviews/conceptual/viewpg_iphoneos/animatingviews/animatingviews.html
You might have to create a custom bar button item using a view or an image, and then animate the properties of the view as digitalHound shows.

Animating two UIView subviews at the same time does not work

For some reason i am not able two animate two subviews postion. I have wrote the following
[self addChildViewController:self.photosViewController];
[self.photosViewController.view setFrame:CGRectMake(0, -self.view.frame.size.height, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:self.photosViewController.view];
[UIView animateWithDuration:1 delay:0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
[self.stepsView setFrame:CGRectMake(0, self.view.frame.size.height, self.view.frame.size.width, self.view.frame.size.height)];
[self.photosViewController.view setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
}
completion:^(BOOL finished) {
if (finished) {
button.tag = 0;
}
}];
self.stepsView is an IBOutlet UIView and self.photosViewController.view is an child view controllers view that has been added to the view.
With the current code only the self.PhotosViewController.view animates. However if i comment out the line where i add the child view controllers view as a subview then the self.stepsView animates correctly.
Even if i add the child view controller and its view before this method is called the same error happens.
Need help as i ran in to this a couple of months back with another app and had to do a dirty hack to get around it and now want to solve this.
Thanks
In the section on view animation in the View Programming Guide there is a specific mention of how to animate subviews.
Basically, you should use transitionWithView:duration:options:animations:completion: rather than animateWithDuration:delay:options:animations:completion:.
The first view will not be visible, because its origin.y is beyond the height of the visible view. If it was not visible when the animation starts, you will of course see nothing.
The second view is changed to fill the screen. Again, what you see depends on its initial position.

Adding transparency to the VC on IB action - iOS

I have a case where I need to open a new UIViewController on IBAction. This new UIViewController is supposed to be transparent. When I do a normal modal transition it hides the old UIViewController. Any suggestions on this?
For your purposes you will want to tell your modal View Controllers view property to change alpha. (best done in the view controllers viewDidLoad)
It's as simple as:
- (void) viewDidLoad
{
[self.view setAlpha:0.5];
}
Now, the other approach would be to just use a new UIView added as a subview of your main view controller. The following will show your how to animate it in.
UIView *myNewView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[myNewView setAlpha:0.0];
[self.view addSubview:myNewView];
[UIView animateWithDuration:1.5 animations:^{
[myNewView setAlpha:0.5];
}];
EDIT: To change the alpha of the background view and preserve the alpha of its subviews, try setting it up like this.
[myNewView setBackgroundColor:[[UIColor blueColor] colorWithAlphaComponent:0.2]];
[myNewViewsSubView setBackgroundColor:[[UIColor redColor] colorWithAlphaComponent:1.0]];

Resources