Saturday, March 13, 2010

Refactoring Suggested items. Creating an animation helper

The first refactoring I'd like to make is to take the animation code that is embedded into a specific callback and make it more general.  To do this I made two refactorings:


  1. Move the ability to make a graphical clone of a UIView to a category on UIView
  2. Create a new animation class for the purpose of holding common animations I would like to reuse, currently it only has one.

Making the UIView Category

The first choice is to make a category of UIView, this will be a place to hang functions that I would like to do to any view.  This will be a file UIView_helper.h and UIView_helper.m.

UIView_Helper.h

do
#import
#import

@interface UIView(AnimationHelper)

//
// Create a image of the current view, and give it a frame 
// identical to the current location.  The image view is autoreleased.
// 
- (UIImageView *)createImageOfView;

@end
This is pretty simple, a simple function that when called will create a UIImageView of the current view and return it.

UIView_Helper.m


#import "UIView_Images.h"
#import


@implementation UIView(AnimationHelper)



//
// Create a image of the current view, and give it a frame 
// identical to the current location.  The image view is autoreleased.
// 
- (UIImageView *)createImageOfView
{
// First getting a view of the current image.
UIGraphicsBeginImageContext(self.bounds.size);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
// this function returns an autoreleased image.
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *imageView=[[UIImageView alloc] initWithImage :viewImage];
imageView.frame=self.frame;
return [imageView autorelease];
}
@end

Making the Animation helper


The next refactoring is to extract the animation code into an object.  This will enable reuse, and keep my actual business logic separate from animation.  In addition it will allow me to update my animation to higher qualities as I get more time.  The current animation is functional, but not as pretty as the Apple animations.

The interface


// An animation helper for some animations to be shared between tasks.
@interface AnimationHelper : NSObject {

}
// This animation will take an image of the source image and move it
// towards the destionation.  This is intended to be a visual indicator.
// Right now all it does is set the frame of the image to be the frame of
// the destionation.  Eventually a more complicated sheering function might be
// nice to have.
- (void) sendViewImageToView : (UIView *)sourceView destinationView:(UIView*) destination;



@end

The code


The code makes use of the UIVIew category defined above, and declares the animation. NOte that to handle the callback for when the first animation is done, and I wish to remove the view, I declare a private category.
// Declare a private category for the animation being over.  This will
// remove the view passed in as context, allowing the image to disappear.
// Eventually more complicated chains of animations might be desired.
@interface AnimationHelper()



- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context;

@end


@implementation AnimationHelper

- (void) sendViewImageToView : (UIView *)sourceView destinationView:(UIView*) destination
{
UIImageView *sourceImage=[sourceView createImageOfView];
UIView *parentView=[sourceView superview];
[parentView addSubview:sourceImage];
[UIView beginAnimations:nil context:sourceImage];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[sourceImage setFrame:destination.frame];

// TODO make this a parameter.   Right now set very short because 
// visual indicating is nice, LONG visual indicating is NOT nice.
[UIView setAnimationDuration:0.25];
[UIView setAnimationDelegate:self];
// Call a selector when we are done with the animation so that it can be
// released.
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
[UIView commitAnimations];
}

// Once the animation is done, remove the view from it's superview.
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
UIView *view=(UIView *)context;
// Remove from superview releases it.
[view removeFromSuperview];
}

@end

Now to use it, all I have to do is this call:
AnimationHelper *animationHelper=[[[AnimationHelper alloc] init] autorelease];
[animationHelper sendViewImageToView:searchBar destinationView:addButton];

The animation helper is declared autorelease because i can't release it in my function, it has a lifespan outside my function, and I didn't want to make it a property that I hang around and release later.  It doesn't crash yet, I'm not fully up on the autorelease rules yet.


The changes in this refactoring can easily be viewed at






No comments:

Post a Comment