UIScrollView inside a movable UIView - ios

I'm attempting to recreate the animation done in the Google Maps app that occurs when you select a location on the map. After selecting a location a UIView pokes up from the bottom of the screen. You can pull that up to reveal a UIScrollView with additional content. I'm curious how they make it so you can only scroll the content inside the UIScrollView when the parent view is at the "top". I understand that you could setScrollEnabled:, but they somehow do it on the fly so that when sliding your finger up the parent view "docks", and then the inner content scrolls, and when you are scrolling the content down, it stops once it reaches the top of the content and starts pulling the header down with it.
Any ideas?

I solved this problem by doing something like this: Create an animation that moves the scroll view's parent from the half-visible position to the top....
- (void)setScrollViewExpanded:(BOOL)expanded {
BOOL isExpanded = self.scrollViewContainer.frame.origin.y == 0.0;
if (isExpanded == expanded) return;
CGRect frame = self.scrollViewContainer.frame;
CGRect newFrame;
if (expanded) {
newFrame = CGRectMake(0, 0, frame.size.width, self.view.frame.size.height);
self.scrollView.delegate = nil;
self.scrollViewContainer.frame = CGRectMake(0, frame.origin.y, frame.size.width, self.view.bounds.size.height);
self.scrollView.delegate = self;
} else {
newFrame = CGRectMake(0, 300, frame.size.width, frame.size.height);
}
[UIView animateWithDuration:1 animations:^{
self.scrollViewContainer.frame = newFrame;
} completion:^(BOOL finished) {
if (!expanded) {
self.scrollView.delegate = nil;
self.scrollViewContainer.frame = CGRectMake(0, 300, self.scrollViewContainer.bounds.size.width, self.view.bounds.size.height-300);
self.scrollView.delegate = self;
}
}];
}
Trigger the animation based on change in scroll view's content offset relative to the top...
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y > 10.0) {
// 10 is a little threshold so we won't trigger this on a scroll view
// "bounce" at the top. alternatively, you can set scrollView.bounces = NO
[self setScrollViewExpanded:YES];
} else if (scrollView.contentOffset.y < 0.0) {
[self setScrollViewExpanded:NO];
}
}
Edit: I changed the expand animation after rechecking my old code. It needs to be a little more complex due to feedback on the content offset while changing the frame. The edit doesn't change the size during the animation, just the origin. It changes the size before or after the animation and blocks the delegate messages temporarily. Also note the scroll view's autoresize mask should be set to fill the container view.

Related

iOS UIView animation when table view scroll?

I want animation like home screen of this app.This screen has a view (with a label on it) on top and a table view under it. When i scroll the table the top view and title on it become small with animation and after a specific point it becomes like navigation bar with title in centre. And the same thing when i scroll down.
Here is what i tried so far
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGPoint offset = scrollView.contentOffset;
NSLog(#"y is::: %f", offset.y);
if (offset.y > 0 && offset.y < 16 && self.topView.frame.size.height > 64) {
[UIView animateWithDuration:0.8 animations:^{
CGRect rect = self.topView.frame;
rect.size.height = rect.size.height-offset.y;
self.topView.frame = rect;
}completion:^(BOOL finish){
}];
}
else if(offset.y <= 0 && offset.y > -16 && self.topView.frame.size.height < 80)
{
[UIView animateWithDuration:0.8 animations:^{
CGRect rect = self.topView.frame;
rect.size.height = 80;
self.topView.frame = rect;
}completion:^(BOOL finish){
}];
}
}
Note that my top view initial height is 80 and i want to make it 64 when scroll up and vice versa.
with this code the view height animated but it depends upon animation duration.So if i scroll fast then it is not working properly.The original app i mentioned have very smooth animation. How could i achieve that?
Screen shot of original App-
These screen shots showing three different scroll position, please note the "MySurgery" text on top.1- Larger text and right align.
2- small text and near centre position
3- smaller text and centralised(like navigation bar)
I think you dont need animation for this, you just need some calculations and setting frame of the top view. like,
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGPoint offset = scrollView.contentOffset;
if (offset.y>0 && offset.y<64) {
[topView layoutIfNeeded];
CGRect viewFrame = topView.frame;
viewFrame.size.height--;
topView.frame = viewFrame;
}
}
Note that layoutIfNeeded is required if your view is using autolayout

iOS animate button while scrolling list

I have view with UITableView. Above this list I have UIButton. I need to implement an animation what will move button vertically according to scrolling on list and return to base location when scrolling is finished. I show scrolling down in pictures bellow:
This is not scrolled list:
This is list scrolled to half:
This is list fully scrolled:
For now I detect start and stop scrolling list events and do animation like that:
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGRect newFrame = button.frame;
newFrame.origin.y = screenHeight - (newFrame.size.height/2.0);
[UIView animateWithDuration:2
animations:^{
button.frame = newFrame;
}];
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGRect newFrame = storedButtonFrame;
[UIView animateWithDuration:2
animations:^{
button.frame = newFrame;
}];
}
I have few issues with this First is that when I scrolling down my animation is animating to then end and I want to animate based on scrolled list eg. when I scroll down list for 10px I would like to move button only for 10px not to the end of list. Second is that I get stop scroll event when begin scroll animation is still running the start animation is blink to the end and the end animation is start animating what is definitly what I dont want. I dont have to much experiance in iOS and I really dont have any ide how can I do this. Have any idea how can I do something like this?
Instead of using scrollViewWillBeginDragging: you could use scrollViewDidScroll: like so:
/// Animate the button position as the scroll view scrolls
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat percentage = scrollView.contentOffset.y / scrollView.contentSize.height;
CGRect frame = _button.frame;
frame.origin.y = scrollView.contentOffset.y + percentage * self.tableView.frame.size.height;
_button.frame = frame;
}
/// Animate the button back to the top-right corner
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGRect frame = _button.frame;
frame.origin.y = scrollView.contentOffset.y;
[UIView animateWithDuration:0.4f
animations:^{
_button.frame = frame;
}];
}
This makes the button follow the scroll indicator as you scroll the list. scrollViewDidScroll: fires very often so the movement is smooth.
When the list stops, it goes back to its default position at the top-right, which you get from contentOffset.y.

Resizing UIView with animation, subview won't animate

Using UIView's animateWithDuration:animations:completion:, I'm resizing a UIView and a subview of that UIView which is a subclass of UITableView.
The UIView resizes fine, but the UITableView doesn't. It does move around a little, but the frame does not update properly and reverts to its original state.
Edit: if I move the resizing to the completion block.... it works. What gives?
tweetTable.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[tweetTable endUpdates];
[UIView animateWithDuration:DURATION animations:^{
CGRect leftFrame = leftPane.frame;
leftFrame.size.width = self.view.frame.size.width - MARGIN;
leftPane.frame = leftFrame;
leftPaneButton.frame = leftFrame;
CGRect tweetFrame = tweetTable.frame;
tweetFrame.size.width = leftPane.frame.size.width;
NSLog(#"%f to %f", tweetTable.frame.size.width, leftPane.frame.size.width);
tweetTable.frame = tweetFrame;
tweetTable.backgroundColor = [UIColor redColor];
tweetTable.alpha = 0.5f;
sideInfo.center = CGPointMake(self.view.frame.size.width - MARGIN + (sideInfo.frame.size.width / 2), sideInfo.center.y);
rightPaneButton.center = sideInfo.center;
} completion:^(BOOL finished) {
leftExtended = TRUE;
[tweetTable beginUpdates];
}];
Check in your storyboard if the UIView has Autoresize Subviews checked. That means that it resizes all of its subviews when the view itself gets resized. That would explain why it works in the completion block.

Animating multiple uiviews

I have to views pannelView and contentView. Pressing a button hides pannelView and expands contentView to the full screen. I have been using this code:
if (sender.selected==NO) {
pannelView.hidden=YES;
contentView.frame=CGRectMake(0, 90, 768, 434);
sender.selected=YES;
}
else {
pannelView.hidden=NO;
contentView.frame=CGRectMake(186, 90, 580, 434);
sender.selected=NO;
}
It switches b/w two states without animation. What should I do to animate them to look pretty? Moreover when some other button is pressed, contentView is updated. I want this view to hide and show with animation in the time content is loading.
Have a look at the UIView documentation and the section on block based animation.
A simple example:
CGRect newFrame;
BOOL hidePanelView;
if (sender.selected==NO) {
hidePanelView = YES;
newFrame = CGRectMake(0, 90, 768, 434);
sender.selected=YES;
} else {
hidePanelView = NO;
newframe = CGRectMake(186, 90, 580, 434);
sender.selected=NO;
}
[UIView animateWithDuration:0.25 animations:^{
contentView.frame = newFrame;
pannelView.hidden = hidePanelView;
}

Creating a larger flip-side view for 'tile' in storyboard

I currently have a Container View Controller which is home to a button. When this is pressed, I want the view to flip and grow, similar to iTunes on the iPad.
Main View Controller Layout:
Flipping the Container:
When the flip button is pressed, I intend to use this code (Inside the container view's View Controller) to flip the container:
FrontVC *cb = [[FrontVC alloc]initWithFrame:CGRectMake(0, 0, 92, 65)];
FlipVC *cf = [[FlipVC alloc]initWithFrame:CGRectMake(0, 0, 92, 65)];
[UIView transitionWithView:self.view
duration:1
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
// Remove last view
for (UIView *subview in self.view.subviews) {
[subview removeFromSuperview];
}
[self.view addSubview:(displayingPrimary ? cb: cf)];
}
completion:^(BOOL finished) {
if (finished) {
displayingPrimary = !displayingPrimary;
}
}];
This works well if the two views are the same size, and I can lay out the views using code. FrontVC and FlipVC are sub-classes of UIView.
I was thinking about doing something like this to move the view to the centre of the screen, but I'm stuck from there. Hey, I don't even know if this would work! Is there a better way to do this?
if (!displayingPrimary) {
self.view.center = CGPointMake(320.0f, 480.0f);
cb.center = CGPointMake(320.0f, 480.0f);
}
else
{
self.view.center = CGPointMake(59, 324);
}
What I Am Aiming For:
Ideally, I would like to be able to design the flip view in storyboard, and have the 'tile' grow, similar to iTunes:
Whereas in my example I would like it to look like this:
How would I be able to design this in storyboard? If I try to make a view controller, I am unable to resize it to the size that I would like the flip size view controller to be.
The FlipView project is quite polished and looks exactly as the iTunes flip does. I used two imageViews for the demo project. The actual flip code is as follows:
- (IBAction)flip
{
UIView *fromView, *toView;
CGPoint pt;
CGSize size;
CGFloat sense;
if(showingView == a) {
fromView = a;
toView = b;
pt = BORIGIN;
size = BRECT.size;
sense = -1;
} else {
fromView = b;
toView = a;
pt = AORIGIN;
size = ARECT.size;
sense = 1;
}
[UIView animateWithDuration:TIME/2 animations:^
{
CATransform3D t = CATransform3DIdentity;
t.m34 = M34;
t = CATransform3DRotate(t, M_PI_2*sense, 0, 1, 0);
containerView.layer.transform = t;
containerView.frame = CRECT; // midpoint
NSLog(#"Container MID Frame %#", NSStringFromCGRect(containerView.frame));
}
completion:^(BOOL isFinished)
{
toView.layer.transform = CATransform3DMakeRotation(M_PI*sense, 0, 1, 0);
[UIView animateWithDuration:TIME/2 animations:^
{
[fromView removeFromSuperview];
[containerView addSubview:toView];
CATransform3D t = CATransform3DIdentity;
t.m34 = M34;
t = CATransform3DRotate(t, M_PI*sense, 0, 1, 0);
containerView.layer.transform = t; //finish the flip
containerView.frame = (CGRect){ pt, size};
} completion:^(BOOL isFinished)
{
NSLog(#"Container Frame %#", NSStringFromCGRect(containerView.frame));
NSLog(#"A Frame %#", NSStringFromCGRect(b.frame));
NSLog(#"B Frame %#", NSStringFromCGRect(b.frame));
toView.layer.transform = CATransform3DIdentity;
containerView.layer.transform = CATransform3DIdentity;
showingView = showingView == a ? b : a;
}];
}];
}
http://dl.dropbox.com/u/60414145/FlipView.zip
EDIT: One way to work around the resizing a real view with real controls in it might have is to take a snapshot of that view, use the snapshot while zooming/flipping, and in the final completion block switch out the image for the real view. That is:
create a UIImage of your current small view when the user taps the image
create a UIImage of the final view, rendered into a context as its natural size
use the two images in the container view, for the animation
in the final completion block, remove your imageView from view and put the second view now in self.view subviews
I did a rough code (not at all perfect) on this (hope it is what you are looking for). Have a look into it. I created a baseView and two flip views, after the first flip, I increased the frame size of baseView and added the second flip view on it.I am not an expert of Story Board, so I havent used it here.
FlipTest
-anoop

Resources