I have a particular scenario that I'm trying to emulate and, being fairly new to Cocoa Touch, I'm not sure of the best way to accomplish it. Pardon my lacking tactical knowledge; hopefully some clear exposition will help.
What I'd Like To Emulate:
The app I'm looking at (in particular) is Beat. Below is an example of one of their UIViews - in particular, notice the gear icon for Settings at the bottom.
When that gear is touched or swiped up, two primary UIView changes occur:
The original UIView is slid up the screen about 90% of the way (the key point being that it does not slide all the way up).
A new UIView is slid up to fill that newly vacated 90% space.
This is the basic functionality that I would like to accomplish.
Implementation Idea #1: Single UIViewController w/ Multiple UIViews
At first, I considered having a single UIViewController manage both the "main" and the "settings" views. In that case, it would be a fairly simple thing to transition these views in the appropriate manner.
That said, this seems a bit cluttered to me. Depending on how robust my two sets of functionality are, that's a recipe to overload a single UIViewController. You might tell me that that's okay, but off the bat, it seems too much.
Implementation Idea #2: Multiple UIViewControllers Within Custom Container ViewController
This is the route I'm currently going down. It separates the two discrete sets of functionality into separate UIViewControllers (contained within a Container ViewController) and transitions between the two via:
- (void)flipFromViewController:(UIViewController *)fromController
toViewController:(UIViewController *)toController
{
CGFloat width = self.view.frame.size.width;
CGFloat height = self.view.frame.size.height;
fromController.view.frame = CGRectMake(0.0f, 0.0f, width, height);
toController.view.frame = CGRectMake(0.0f, height, width, height);
[self addChildViewController:toController];
[fromController willMoveToParentViewController:nil];
[self transitionFromViewController:fromController
toViewController:toController
duration:0.5f
options:UIViewAnimationOptionTransitionNone
animations:^(void) {
fromController.view.frame = CGRectMake(0.0f, -(height - 100.0f), width, height);
toController.view.frame = CGRectMake(0.0f, 100.0f, width, height);
}
completion:^(BOOL finished) {
[fromController removeFromParentViewController];
[toController didMoveToParentViewController:self];
}];
}
The problem with this is the transition: it doesn't seem to stop "90% of the way". It looks more like it's intended to completely transition out an "old" controller and in a "new" controller, even though my frame adjustments on the two UIViews are not supposed to be "complete" moves.
Where I'd Like Guidance
I'm not asking for a complete solution - your expertise would be too expensive. :) That said, being fairly new to this, I would love your insight on what the right approach would be. Please let me know if I can provide further information.
Thanks!
I do think your 2nd method is on the right track, and your intuition about using transitionFromViewController:ToViewController is also right -- I wouldn't use that method if you want both view controllers to be present and active. So, I would have the controller with the gear view be a child view controller of a custom container controller, then add the second child off screen to the bottom like you have. Then animate both views up using animateWithDuration:... At the end of that, animation, you should have what you want, and you container controller will have two children.
Related
Anybody have any idea how this is done?
http://youtu.be/r_cII4_aq_A
In general, the idea is awesome, but I would like to know how to do each specific thing. In the video, the pages are being swiped too fast so you can't see, but as you transition from one page to the next, each pixel smoothly transitions to it's new color. Also, it's really cool how the icon gets smaller to a minimum size as you transition away from a screen.
Maybe there's some 3rd party library that provides a protocol and it's relatively easy to implement, but I can't find it. If there's not, I'm thinking it's just one view controller with many views side by side and as you drag your finger, it calculates where each view needs to be..and what color every pixel needs to be.
I imagine you already have it by now. But in case you still have any doubts, I made gist that does the animation: https://gist.github.com/mnmaraes/9536364
Anyways, have fun.
It's a fade animation, so:
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
_backgroundImageView.image = nextImage;
} completion:nil];
should do the trick for the background part.
For the foreground/icon part you can animate the transform to scale and translate the views as they slide in and out.
I'm using the concept of the ui page control.
For example, I have multiple similar views. Let say 10 news articles. I put them in a a page control and am able to swipe between them.
However, I want to mimic the animation that the UINavController does. Is this possible? ie: not have the pages scroll end to end but instead a slight overlap and effect where one panel slides out at twice the speed of the one below it sliding in.
Any Ideas?
If i am not getting wrong understanding of your question..
As this is not possible to do with existing page controls you need your own logic
This is how it should be handled, you will need to adjustments as per your requirement..
Rough logic
[self.view addSubview:nextArticleView];
nextArticleView.frame = // set offscreen frame, in the direction you want it to appear from
//Set more time as newArticle should overlap to existing articles view
[UIView animateWithDuration:10.0
animations:^{
nextArticleView.frame = // desired end location (current articles initial frame)
}];
//set less time as current article should slide fast
[UIView animateWithDuration:5.0
animations:^{
self.view.frame = // desired end location (off screen)
}];
I am trying to flip a UIView around one edge of the view, as if the view were a page of a calendar with a rigid page moving over like so : Calendar.
I am trying to do it like so :
[UIView transitionWithView:self.upperCard
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromBottom
animations:^{
topView.frame = [self bottomHalfRectFromBounds];
bottomView.frame = [self topHalfRectFromBounds];
topView.flippedOver = YES;
bottomView.flippedOver = NO;
}
completion:NULL];
[self setNeedsDisplay];
The only problem with this method is that because the animation of the view's frame is Linear and so is the flipping animation the animation's are out of time with each other (This is due to the fact that flipping at a constant velocity the area which is visible of the view is proportional to Cos(t), learn some maths if you didn't know that ;P).
So basically I'm either looking for a way to make the frame animation have an easing function... or a completely alternative method... I don't want this to look like a page curl as it is going to be used for a scoreboard app, so please don't just tell me to use the UIViewAnimationOptionCurlDown option :P
Thanks for your time!
In general, animating your view’s frame is not a good way to approach this: it causes the view to have to redraw itself at every step of the animation, and, as you’ve noticed, doesn’t look like a flip so much as a linear scale.
Check out this answer—specifically the second part of it, discussing how to do it in CA—for a better approach.
I'm adding this menu to an app I'm working on: http://mobiledevelopertips.com/open-source/ios-open-source-animated-menu.html
I'm relatively green to Objective C (only been working on it for less than a month) and I'm not entirely sure how to do the following:
1) I want to add a gray overlay to the entire screen when I hit the button to open the menu. I've looked for solutions but a lot of people seem to recommend DSActivityView which doesn't work for me... I don't need that loading bubble. I guess I could download the source and remove the bubble, but that might require more effort than it's worth.
I would think that I could just instantiate an imageView, drop it at 0,0 and expand it to the bounds of the screen, sourced with a transparent gray PNG file...like
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"transparent_gray.png"]];
imageView.frame= CGRectMake (0,0,screenWidth,screenHeight);
[viewController addSubview:imageView];
However, this approach probably won't work ( I'm guessing it won't cover the nav controllers like tab bar and status bar). Furthermore, I'm not really sure how I'd get to access the viewController from within AwesomeMenu. I assume I'd have to pass a reference of the viewController that is instantiating the AwesomeMenu into one of AwesomeMenu's functions in order to be able to deploy an imageView into the viewController?
2) I want to write a delegate that will fire when the opening menu animations stop, so I can write text onto the overlay'd screen. Is there a super easy way to do this or am I going to have to just guestimate with some timer start/callback and make the callback write the text onto my screen? Oh - I've never written a delegate before but I assume it becomes slightly complicated when I want them to fire upon animation end.
Um, I think you have some preconceived notions about the way UIKit works. For 1), I suggest searching SO for "view covers screen" and get a better understanding of the issue, especially associated with view animation. Secondly, there are many ways to accomplish your 2) item. If you have the source to AwesomeMenu you can just modify whatever animations it performs. If the animation was done with animateWithDuration:animations: you can just add a completion: block. If you have a need to do your completion animation from several places, you might consider a delegate. You might be able to write a category for AwesomeMenu to add the functionality. In your case, I think a simple code modification is all you need. Hard to tell without more code/facts, though.
I've built a UIControl subclass to display a 1-month calendar view on
an iPhone. Most months require 5 weeks to display the dates, but
some months need 6, so I've built the control to dynamically resize
itself as needed. I'm using UIView animation to change the frame of
the control here.
The problem is, I now need the other controls on the screen to
move/resize when the calendar changes size. And I really need that
to happen with the animation of the calendar control changing size.
Ideally, I'd do this without coding a bunch of details in my calendar
control about other controls on the screen.
What's the best strategy here? I was hoping I could somehow anchor
the other controls to the frame of the calendar control and have the
platform adjust their location/size as it animates the frame change.
But, thus far, I can't find any combination of struts and springs to
make that happen.
Do I just need to bite the bullet and add my other on-screen controls
to the animation happening inside my calendar control?
I'll be interested to see if there are better answers to this.
At this point, all I know to do is override setFrame on your calendar view and when it changes, send setNeedsLayout to its superview.
But I'm not sure if standard views will autoresize this correctly. Generally geometry flows down the view tree, not up, and you want it to do both.
You may have to implement layoutSubviews on the containing view.
Move the animation logic out of the specific view and into a view controller that manages all of the controls. The view can still figure out its own proper size, and let the view controller ask. For instance:
[self.calendarView setDate:date];
CGSize calendarSize = [self.calendarView sizeForDate:date];
[UIView animateWithDuration:...
animations:^{
... re-layout everything, including the calendarView ...
}];
Another, similar approach:
[self.calendarView setDate:date];
[UIView animateWithDuration:...
animations:^{
[self.calendarView sizeToFit];
... re-layout everything else ...
}];
There are lots of similar approaches based on your preferences. But the key is to move the logic out of the specific view. Usually a view controller is the best solution. If the controls make a logical collection that could go into a single UIView, then you could have that "collection" UIView manage the same thing in its layoutSubviews, but it's more common that a view controller is a better solution here.
Thanks for the help. I tried both of these approaches with success. The override of setFrame and implementation of layoutSubviews worked, but the other controls jumped to their new locations rather than animating to those locations as the calendar control grew.
The approach of moving the other controls during the animation is what I had to go with. However, I wanted to keep the logic of the control pretty self-contained for re-use, so I left the animation in the control but added a delegate to react to size change, and put the delegate call inside the animation block. In full disclosure, I am also animating the new month's calendar onto the control while I'm growing the control, and this way I could do both of those things in the animation block.
So, the end code looks something like this:
// inside the calendar control:
[UIView animateWithDuration:0.5 animations:^{
self.frame = newOverallFrame; // animate the growth of the control
_offScreenCalendar.frame = newOnScreenFrame; // animate new month on screen
_onScreenCalendar.frame = newOffScreenFrame; // animate old month off screen
if (self.delegate)
{
[self.delegate handleCalendarControlSizeChange:newOverallFrame]; // animate other controls per the delegate
}
}];