Skip to content

Commit

Permalink
Finished subclasing support, completed beta quality documentation, ne…
Browse files Browse the repository at this point in the history
…ed to add subcloassing testing, unit testing
  • Loading branch information
nathanday committed Jul 22, 2011
1 parent ba19c5e commit cc1ace9
Show file tree
Hide file tree
Showing 9 changed files with 1,000 additions and 635 deletions.
22 changes: 22 additions & 0 deletions Classes/NDRevealView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// NDRevealView.h
// NDRevealView
//
// Created by Nathan Day on 22/07/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface NDRevealView : UIView

@property (nonatomic, getter=isExpanded) BOOL expanded;
@property (retain) IBOutlet UIView * hideContent;

- (IBAction)toggleExpansion:(id)sender;
- (IBAction)expansion:(id)sender;
- (IBAction)compact:(id)sender;

- (void)setExpanded:(BOOL)expanded animate:(BOOL)animate;

@end
127 changes: 127 additions & 0 deletions Classes/NDRevealView.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
//
// NDRevealView.m
// NDRevealView
//
// Created by Nathan Day on 22/07/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "NDRevealView.h"

@interface NDRevealView ()
{
@private
BOOL expanded;
UIView * hideContent;
}

@end

@implementation NDRevealView

@synthesize expanded,
hideContent;

#pragma mark -
#pragma mark Manually implemented properties

- (void)setExpanded:(BOOL)anExpanded
{
[self setExpanded:anExpanded animate:YES];
}

- (void)setExpanded:(BOOL)anExpanded animate:(BOOL)anAnimate
{
if( anExpanded != expanded )
{
CGRect theFrame = self.frame;
if( anAnimate )
{
if( anExpanded )
{
theFrame.size.height += CGRectGetHeight(self.hideContent.frame);
[UIView beginAnimations:@"animation2" context:NULL];
[UIView setAnimationDuration:0.3];
self.frame = theFrame;
[UIView commitAnimations];

self.hideContent.hidden = NO;
[UIView beginAnimations:@"animation1" context:NULL];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelay:0.3];
self.hideContent.alpha = 1.0;
[UIView commitAnimations];
}
else
{
[UIView beginAnimations:@"animation1" context:NULL];
[UIView setAnimationDuration:0.3];
self.hideContent.alpha = 0.0;
[UIView commitAnimations];

theFrame.size.height -= CGRectGetHeight(self.hideContent.frame);
[UIView beginAnimations:@"animation2" context:NULL];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(expandAnimationDidStop:finished:context:)];
[UIView setAnimationDelay:0.1];
self.frame = theFrame;
[UIView commitAnimations];
}
}
else
{
if( anExpanded )
{
theFrame.size.height += CGRectGetHeight(self.hideContent.frame);
self.frame = theFrame;
self.hideContent.hidden = NO;
self.hideContent.alpha = 1.0;
}
else
{
self.hideContent.alpha = 0.0;
theFrame.size.height -= CGRectGetHeight(self.hideContent.frame);
self.frame = theFrame;
}

}
expanded = anExpanded;
}
}

- (void)expandAnimationDidStop:(NSString *)anAnimationID finished:(NSNumber *)aFinished context:(void *)aContext
{
self.hideContent.hidden = !self.isExpanded;
}

#pragma mark - View lifecycle

- (void)awakeFromNib
{
[super awakeFromNib];
[self setExpanded:NO animate:NO];
}

#pragma mark - creation and destruction

- (id)initWithFrame:(CGRect)aFrame
{
if( (self = [super initWithFrame:aFrame]) != nil )
expanded = YES;
return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
if( (self = [super initWithCoder:aDecoder]) != nil )
expanded = YES;
return self;
}

#pragma mark - Actions
- (IBAction)toggleExpansion:(id)aSender { self.expanded = !self.isExpanded; }
- (IBAction)expansion:(id)aSender { self.expanded = YES; }
- (IBAction)compact:(id)aSender { self.expanded = NO; }

@end
120 changes: 79 additions & 41 deletions Classes/NDRotator.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,70 +70,96 @@ enum NDThumbTint
A NDRotator object is a visual control used to select one or two values from a continuous range of values. Rotator are always displayed as circular dials. An indicator, or thumb, notes the current value of the rotator and can be moved by the user to change the setting with a turning action and the choice of radius action as well for a second value.
### Subclassing Notes
NDRotator is designed to be overridden to change the appearance there, MORE TO COME.
The NDRotator class is designed to be subclassed to change the appearance. NDRotator performs caching of it elements to allow for smooth animation on low power devices like the iPhone, the methods to override work with this caching so you do not have to reimplement this yourself.
#### Methods to Override
When subclassing NDRotator, there are only a handful of methods you need to override. NDRotator is designed to do as much as possible to implement you own rotator style control, it is based around a control made up of two parts which do not change appearance for changing values but instead the position of a thumb element changes with respect to the body of the control.
if you need to, you can override any of the following methods in your NDRotator subclasses:
- Initialization:
initWithFrame:, initWithCoder: -Just like subclassing and <UIView> you may want to override the initialisation methods initWithFrame: and initWithCoder: to add the initialisation of you own properties.
- Coding:
initWithCoder:, encodeWithCoder: -If you want to add your own values to be encoded and decoded you will then have to override these two methods you should call the super implementation.
- Drawing:
drawBodyInRect:hilighted:, drawThumbInRect:hilighted: -you will need to override these two methods to change the appearance of Rotator's, unless you want to just modify the default look, for example you could just override drawThumbInRect:hilighted: if you just want to change the thumb but keep the same body, you do no want to call the super implementations in your implementations.
bodyRect, thumbRect -If you override <drawBodyInRect:hilighted:> <drawThumbInRect:hilighted:>, you will need to override the corresponding rect property to give NDRotator information on how to calculating the thumb position.
- Behaviour:
setStyle: -This method is can be overriden if want to limit which styles are supported, for example, the <NDRotatorStyleDisc> style offten will not be appropriate, if you are the only user of your subclass, then this is not nessecary as you can choose to just not use it this way.
*/
@interface NDRotator : UIControl <NSCoding>

/**
@name Accessing the Rotator’s Value
*/
/**
This is a value taken from the <angle> property and mapped from the domain (<minimumDomain>,<maximumDomain>) to the range (<minimumValue>,<maximumValue>).
*/
@property(assign) CGFloat value;
@property(assign) CGFloat value;
/**
Contains the angle of the receiver in radians.
This value will be constrained by the values (<minimumDomain>,<maximumDomain>) and so can represent a range of values greater than one turn.
*/
@property(assign,nonatomic) CGFloat angle;
/**
Contains the radius value of the receiver where 0.0 puts the thumb at the center and 1.0 puts the thumb at margin.
The values can be greater than 1.0, to reflect user movements outside of the control.
*/
@property(assign,nonatomic) CGFloat radius;
/**
Contains the thumb point where (0.0,0.0) is the center, (1.0,0.0) is at 3 oclock and (0.0,-1.0) is at 12 oclock etc.
The point can go beyound the bounds (-1.0,-1.0) and (1.0,1.0) for <radius> values greated the 1.0.
*/
@property(assign) CGPoint cartesianPoint;
/**
Contains the thumb point where (0.0,0.0) is the center, (1.0,0.0) is at 3 oclock and (0.0,-1.0) is at 12 oclock etc. The value is generated from a <radius> constrained to (0.0,1.0).
This value is similar to <cartesianPoint> give a <radius> constrained to (0.0,1.0).
*/
@property(readonly) CGPoint constrainedCartesianPoint;

/**
@name Accessing the Rotator’s Value Limits
*/

/**
Contains the minimum value of the receiver.
If you change the value of this property, and the current <value> of the receiver is below the new minimum, the current <value> is adjusted to match the new minimum value automatically.
The default value of this property is 0.0.
*/
@property(assign) CGFloat minimumValue;
@property(assign) CGFloat minimumValue;
/**
Contains the maximum value of the receiver.
If you change the value of this property, and the current <value> of the receiver is above the new maximum, the current <value> is adjusted to match the new maximum value automatically.
The default value of this property is 1.0.
*/
@property(assign) CGFloat maximumValue;
@property(assign) CGFloat maximumValue;
/**
Contains the minimum <angle> of the receiver.
The default value of this property is 0.0.
*/
@property(assign) CGFloat minimumDomain;
@property(assign) CGFloat minimumDomain;
/**
Contains the maximum <angle> of the receiver.
The default value of this property is 2.0pi.
*/
@property(assign) CGFloat maximumDomain;
@property(assign) CGFloat maximumDomain;
/**
Contains the value used to determin how vertical movement is mapped to angular movement of the control when the style is <NDRotatorStyleLinear>.
The <angle> is propertional to y-value * <linearSensitivity>.
The default value of this property is 0.05.
*/
@property(assign) CGFloat linearSensitivity;
/**
Contains the angle of the receiver in radians.
This value will be constrained by the values (<minimumDomain>,<maximumDomain>) and so can represent a range of values greater than one turn.
*/
@property(assign,nonatomic) CGFloat angle;
/**
Contains the radius value of the receiver where 0.0 puts the thumb at the center and 1.0 puts the thumb at margin.
The values can be greater than 1.0, to reflect user movements outside of the control.
*/
@property(assign,nonatomic) CGFloat radius;
/**
Contains the thumb point where (0.0,0.0) is the center, (1.0,0.0) is at 3 oclock and (0.0,-1.0) is at 12 oclock etc.

The point can go beyound the bounds (-1.0,-1.0) and (1.0,1.0) for <radius> values greated the 1.0.
*/
@property(assign) CGPoint cartesianPoint;
/**
Contains the thumb point where (0.0,0.0) is the center, (1.0,0.0) is at 3 oclock and (0.0,-1.0) is at 12 oclock etc. The value is generated from a <radius> constrained to (0.0,1.0).
This value is similar to <cartesianPoint> give a <radius> constrained to (0.0,1.0).
@name Modifying the Rotator’s Behavior
*/
@property(readonly) CGPoint constrainedCartesianPoint;
@property(assign) CGFloat linearSensitivity;
/**
Contains the enum value used to determine how the reciever interacts with the user.
*/
Expand All @@ -154,6 +180,10 @@ If YES, the slider sends update events continuously to the associated target's a
The default value of this property is YES.
*/
@property(nonatomic, getter=isContinuous) BOOL continuous;

/**
@name Changing the Rotator’s Appearance
*/
/**
Contains the value used to set the color of the thumb.
Expand All @@ -162,36 +192,44 @@ The default value of the property is <NDThumbTintGrey>.
@property(nonatomic) enum NDThumbTint thumbTint;

/**
@name methods and properties to call when subclassing <NDRotator>.
@name Methods to call when subclassing
*/

/**
Delete the thumb cache causing it to be recalculated
This method is for subclass to call if the thumb images changes and needs to be redrawn
Delete the thumb cache causing it to be recalculated
This method is for subclass to call if the thumb images changes and needs to be redrawn
*/
- (void)deleteThumbCache;
/**
Delete the disc cache causing it to be recalculated
This method is for subclass to call if the disc images changes and needs to be redrawn
Delete the disc cache causing it to be recalculated
This method is for subclass to call if the disc images changes and needs to be redrawn
*/
- (void)deleteDiscCache;
- (void)deleteBodyCache;

/**
@name methods and properties to override to change the apperance of a <NDRotator>, these methods are not yet finalized.
@name Methods and properties to override when subclassing
*/

/**
The rect used for the controls interactive surface.
This rect may be smaller than the bounds of the control to allow for shadow effects. This rect is used to workout where the thumb position, the center of the rect is the point which the thumb rotates around.
The rect used for the controls body.
This rect may be smaller than the bounds of the control to allow for shadow effects. This rect is used to workout where the thumb position, the center of the rect is the point which the thumb rotates around.
*/
@property(readonly) CGRect controlRect;
@property(readonly) CGRect bodyRect;
/**
The rect used to contain the thumb image.
This point (0.0,0.0) in the rect used to position the thumb, for a symetrical thumb the point (0.0,0.0) is the center of the rect.
The rect used to contain the thumb image.
This point (0.0,0.0) in the rect used to position the thumb, for a symetrical thumb the point (0.0,0.0) is the center of the rect.
*/
@property(readonly) CGRect thumbRect;

- (BOOL)drawDiscInRect:(CGRect)rect hilighted:(BOOL)hilighted;
/**
draw the control body into the given <rect>.
The <rect> supplied is the size of the reciever <bounds> of the control not the rect returned from the property <bodyRect>. The drawing is cached and so is not called all the time, to force the body to be redrawed again call <deleteBodyCache>. This methods is called twice, <hilighted> set and unset, if there is no difference between the two versions then return NO for one of the versions this will result in one version being used for both hilighted and unhilighted.
*/
- (BOOL)drawBodyInRect:(CGRect)rect hilighted:(BOOL)hilighted;
/**
draw the control thumb into the given rect.
The <rect> supplied is the size of the rect returned from <thumbRect>, but the origin is not. The drawing is cahced and so is not called all the time, to force the thumb to be redrawed again call <deleteThumbCache>. This methods is called twice, <hilighted> set and unset, if there is no difference between the two versions then return NO for one of the versions this will result in one version being used for both hilighted and unhilighted.
*/
- (BOOL)drawThumbInRect:(CGRect)rect hilighted:(BOOL)hilighted;

@end
Loading

0 comments on commit cc1ace9

Please sign in to comment.