how to build an undo stack in iOS/core graphics - cocoa-touch

I'm trying to add an undo / redo capability to a set of touches..
I have this code for touchesBegan and moved:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"%s", __FUNCTION__);
mouseSwiped = NO;
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2) {
[self eraseButtonTapped:self];
return;
}
lastPoint = [touch locationInView:self.view];
lastPoint.y -= 20;
[self.undoPath addObject:WHATGOESHERE];
// Remove all paths from redo stack
[self.redoStack removeAllObjects];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
//NSLog(#"%s", __FUNCTION__);
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
currentPoint.y -= 20;
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, brush);
CGContextSetRGBStrokeColor(context, red, green, blue, 1.0);
CGContextBeginPath(context);
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y);
CGContextStrokePath(context);
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
[self.undoPath addObject:WHATGOESHERE];
UIGraphicsEndImageContext();
NSLog(#"Touches Moved undoPath contains %i objects", [self.undoPath count]);
// Remove all paths from redo stack
[self.redoPath removeAllObjects];
lastPoint = currentPoint;
}
I think that if I can figure how to populate the undo stack, that I can iterate through the stack to undo redo touches.. Maybe I'm all wet. I sure would appreciate some help...
Thanks
..I have asked a similar question before, but I've restarted the project in a different form as the last way was not satisfactory.

I finally solved this by managing arrays.
For each stroke, there is an addition to a buffer array:
[self.currentColoredPath.path moveToPoint:[touch locationInView:self]];
[self.currentArray addObject:self.currentColoredPath];
// Remove all paths from redo stack
[self.redoStack removeAllObjects];
Then the Undo and Redo methods look like this:
-(void)undoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.currentArray count] == 0) {
//nothing to undo
return;
}
DrawingPath *undonePath = [self.currentArray lastObject];
[self.currentArray removeLastObject];
[self.redoStack addObject:undonePath];
[self setNeedsDisplay];
}
-(void)redoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.redoStack count] == 0) {
// nothing to redo
return;
}
DrawingPath *redonePath = [self.redoStack lastObject];
[self.redoStack removeLastObject];
[self.currentArray addObject:redonePath];
[self setNeedsDisplay];
}
I hope this helps others.
UPDATE - This is in response to the question below: "What is currentColoredPath?"
#property (strong,nonatomic) DrawingPath *currentColoredPath;
This refers to a class DrawingPath, which I wrote as follows:
.h
#import <Foundation/Foundation.h>
#interface DrawingPath : NSObject {
NSString *brushSize;
}
#property (strong, nonatomic) NSString *brushSize;
#property (strong,nonatomic) UIColor *color;
#property (strong,nonatomic) UIBezierPath *path;
- (void)draw;
- (void)brushChange;
.m
#import "DrawingPath.h"
#implementation DrawingPath
#synthesize path = _path;
#synthesize color = _color;
#synthesize brushSize = _brushSize;
float brush = 12;
- (id)init {
//NSLog(#"%s", __FUNCTION__);
if (!(self = [super init] ))
return nil;
brushSize = [[NSUserDefaults standardUserDefaults] objectForKey:#"brushKey"];
[self brushChange];
_path = [[UIBezierPath alloc] init];
_path.lineCapStyle=kCGLineCapRound;
_path.lineJoinStyle=kCGLineJoinRound;
[_path setLineWidth:brush];
return self;
}
- (void)draw {
//NSLog(#"%s", __FUNCTION__);
[self.color setStroke];
[self.path stroke];
}
- (void)brushChange { //from notification
//NSLog(#"%s", __FUNCTION__);
brushSize = [[NSUserDefaults standardUserDefaults] objectForKey:#"brushKey"];
//NSLog(#"DrawingPath - brushSize is %#: ", brushSize );
//NSLog(#"DrawingPath - brush is %f: ", brush );
}

Related

How to draw Signature on UIView

I am new in ios.And I need to create a textview or label in which i can sign.
Like this image.
You can draw signature on UIView for that first subclass UIView and your subclass of UIView should be something like,
SignatureView.h
#import <UIKit/UIKit.h>
#interface SignatureView : UIView{
UIBezierPath *_path;
}
- (void)erase;
#end
SignatureView.m
#import "SignatureView.h"
#implementation SignatureView
- (void)drawRect:(CGRect)rect {
_path.lineCapStyle = kCGLineCapRound;
[_path stroke];
}
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame: frame];
if (self) {
[self setMultipleTouchEnabled: NO];
_path = [UIBezierPath bezierPath];
[_path setLineWidth:2.0];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[_path moveToPoint:[mytouch locationInView:self]];
[_path addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[_path addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
- (void)erase {
_path = nil; //Set current path nil
_path = [UIBezierPath bezierPath]; //Create new path
[_path setLineWidth:2.0];
[self setNeedsDisplay];
}
Then you can import SignatureView.h in any your view controller and can instantiate signature view something like,
SignatureView *signView= [[ SignatureView alloc] initWithFrame: CGRectMake(10, 10, self.view.frame.size.width-40, 200)];
[signView setBackgroundColor:[UIColor whiteColor]];
signView.layer.borderColor = [[UIColor lightGrayColor]CGColor];
signView.layer.borderWidth = 1.0;
[self.view addSubview:signView];
And on that view you can draw your signature!
And you can call erase method to erase the signature!
This my solution.
First I created the SignatureDrawView class.In side the SignatureDrawView class I wrote the function for the draw the signature.
SignatureDrawView.h
#import <UIKit/UIKit.h>
#interface SignatureDrawView : UIView
#property (nonatomic, retain) UIGestureRecognizer *theSwipeGesture;
#property (nonatomic, retain) UIImageView *drawImage;
#property (nonatomic, assign) CGPoint lastPoint;
#property (nonatomic, assign) BOOL mouseSwiped;
#property (nonatomic, assign) NSInteger mouseMoved;
- (void)erase;
- (void)setSignature:(NSData *)theLastData;
- (BOOL)isSignatureWrite;
#end
SignatureDrawView.m
#import "SignatureDrawView.h"
#implementation SignatureDrawView
#synthesize theSwipeGesture;
#synthesize drawImage;
#synthesize lastPoint;
#synthesize mouseSwiped;
#synthesize mouseMoved;
#pragma mark - View lifecycle
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (id)initWithCoder:(NSCoder*)coder
{
if ((self = [super initWithCoder:coder]))
{
drawImage = [[UIImageView alloc] initWithImage:nil];
drawImage.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
[self addSubview:drawImage];
self.backgroundColor = [UIColor whiteColor];
mouseMoved = 0;
}
return self;
}
#pragma mark touch handling
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches)
{
NSArray *array = touch.gestureRecognizers;
for (UIGestureRecognizer *gesture in array)
{
if (gesture.enabled & [gesture isMemberOfClass:[UISwipeGestureRecognizer class]])
{
gesture.enabled = NO;
self.theSwipeGesture = gesture;
}
}
}
mouseSwiped = NO;
UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self];
UIGraphicsBeginImageContext(self.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 3.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
mouseMoved++;
if (mouseMoved == 10) {
mouseMoved = 0;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if(!mouseSwiped)
{
UIGraphicsBeginImageContext(self.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 3.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
self.theSwipeGesture.enabled = YES;
mouseSwiped = YES;
}
#pragma mark Methods
- (void)erase
{
mouseSwiped = NO;
drawImage.image = nil;
}
- (void)setSignature:(NSData *)theLastData
{
UIImage *image = [UIImage imageWithData:theLastData];
if (image != nil)
{
drawImage.image = [UIImage imageWithData:theLastData];
mouseSwiped = YES;
}
}
- (BOOL)isSignatureWrite
{
return mouseSwiped;
}
#end
Next in ViewController I created the UIImageView with UIView.
ViewController.h
#import <UIKit/UIKit.h>
#import "SignatureDrawView.h"
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet SignatureDrawView *drawSignView;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize drawSignView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)actionSave:(id)sender
{
// code for save the signature
UIGraphicsBeginImageContext(self.drawSignView.bounds.size);
[[self.drawSignView.layer presentationLayer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *postData = UIImageJPEGRepresentation(viewImage, 1.0);
....Then do your stuff to save this in DB or server
}
- (IBAction)actionCancel:(id)sender
{
//code for cancel the signature
[self.drawSignView erase];
}
- (IBAction)actionClear:(id)sender
{
//code for clear the signature
[self.drawSignView erase];
}
#end
NOTE:When you set the view in xib first identity inspector(it is left
> side in utilities).Then click the drop down box of class(it is part of
Custom Class).Select or choose SignatureDrawView.After that hook up
the view from xib or storyboard to ViewController.h
Below is the output screenshots
Also

iOS8: How to clear a UIView from a UIViewController

I'm trying to update my app to use a storyboard with auto-layout. Using a XIB, I have this working fine. My app has a view controller with a subView defined in Interface Builder. I draw in the subView.
That works.
But I cannot clear (or undo/redo). I can see that the UIView methods are invoked, but I must not be doing something I'm supposed to do.
Here are some code snips, and I'd appreciate some help:
VC simply calls the view:
- (IBAction)eraseButtonTapped:(id)sender {
NSLog(#"%s", __FUNCTION__);
savedImage.image = drawImage.image;
[drawingView eraseButtonClicked];
}
UIView:
- (void)eraseButtonClicked {
NSLog(#"%s", __FUNCTION__);
self.bufferArray = [self.currentArray mutableCopy];
[self.currentArray removeAllObjects];
[self setNeedsDisplay];
}
Both functions log..
These are the touch methods:
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"%s", __FUNCTION__);
self.currentColorPath = [[DrawingPath alloc] init];
[self.currentColorPath setColor:self.currentColor];
UITouch *touch= [touches anyObject];
[self.currentColorPath.path moveToPoint:[touch locationInView:self]];
[self.currentArray addObject:self.currentColorPath];
[self.redoStack removeAllObjects];
lastPoint = [touch locationInView:self];
lastPoint.y -= 20;
if ([touch tapCount] == 2) {
[self alertOKCancelAction];
return;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"%s", __FUNCTION__);
UITouch *touch = [touches anyObject];
[self.currentColorPath.path addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
CGPoint currentPoint = [touch locationInView:self];
currentPoint.y -= 20;
lastPoint = currentPoint;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"%s", __FUNCTION__);
self.currentColorPath = nil;
}
The view calls a separate object to handle the drawing.. This is a code snippet (removing non-relevant bits).
- (id)init {
//NSLog(#"%s", __FUNCTION__);
if (!(self = [super init] ))
return nil;
path = [[UIBezierPath alloc] init];
_path.lineCapStyle=kCGLineCapRound;
_path.lineJoinStyle=kCGLineJoinRound;
[_path setLineWidth:brush];
return self;
}
- (void)draw {
NSLog(#"%s", __FUNCTION__);
[self.color setStroke];
[self.path stroke];
}

CCSprite disappears for unknown reason

-(void)touchBegan:(UITouch*)touch withEvent:(UIEvent*)event {
CGPoint touchPoint = [touch locationInNode:self];
[_gameBall setPosition:CGPointMake(touchPoint.x,self.gameBall.position.y)];
}
After a touch the _gameball sprite is not visible anymore, any reason why this happens?I logged it and isvisible for gameball is true and the touchpoint is always within the content size of my CCNode.
#import "GameScene.h"
#interface GameScene()
#property (nonatomic,strong) CCSprite* gameBall;
#end
#implementation GameScene
#synthesize gameBall = _gameBall;
+(GameScene*)gameInstance
{
return [[self alloc]init];
}
-(id)init
{
self = [super init];
if (self) {
//Implement
//user interaction
self.userInteractionEnabled = YES;
//Create the ball
_gameBall = [CCSprite spriteWithImageNamed:#"small_blue_ball.png"];
_gameBall.position = ccp(0.5f,0.1f);
_gameBall.positionType = CCPositionTypeNormalized;
[self addChild:_gameBall];
}
return self;
}
-(void)onEnter
{
[super onEnter];
}
-(void)onExit
{
[super onExit];
}
-(void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchPoint = [touch locationInNode:self];
touchPoint = [self convertToNodeSpace:touchPoint];
[_gameBall setPosition:CGPointMake(touchPoint.x, self.gameBall.position.y)];
NSLog(#"%f , %f",_gameBall.position.x,_gameBall.position.y);
}
-(void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
}
#end
that was the .m file
now the .h file
#import "cocos2d-ui.h"
#import "cocos2d.h"
#interface IntroScene : CCScene
+(CCScene*)scene;
#end
CGPoint touchPoint = [touch locationInNode:self];
touchPoint = [self convertToNodeSpace:touchPoint];
might be your problem.. try changing it to:
CGPoint touchPoint = [touch locationInView:[touch view]];
touchPoint = [self convertToNodeSpace:touchPoint];
-edit-
ok, try:
CGPoint touchPoint = [touch locationInView:[touch view]];
touchPoint = [[self parent] convertToNodeSpace:touchPoint];
-edit2-
just noticed the cgpointmake:
[_gameBall setPosition:CGPointMake(touchPoint.x, self.gameBall.position.y)];
might not do anything special, but you should keep your code monotone, as in if you used _gameball.position then also use _gameball.position.y
So might want to change it to:
_gameBall setPosition:CGPointMake(touchPoint.x, _gameBall.position.y)];
-edit3-
this seems to work for me:
CGPoint touchPoint = [touch locationInView:[touch view]];
touchPoint = [[_gameBall parent] convertToNodeSpace:touchPoint];
[_gameBall setPosition:ccp(touchPoint.x, _gameBall.position.y)];
-Final edit-
Since you are using cocos2d, also use their ccTouchesBegan function.. Change it to:
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray* touchArray = [touches allObjects];
for (UITouch* touch in touchArray)
{
CGPoint touchPoint = [touch locationInView:[touch view]];
touchPoint = [_gameBall convertToNodeSpace:touchPoint];
[_gameBall setPosition:ccp(touchPoint.x, _gameBall.position.y)];
break;
}
}
if it doesn't register touches, then add: [self setTouchEnabled:YES]; to your scene.

cocos2d ccTintTo, implementing an endless changing color label

Instead of writing all those lines at the init method of HelloWorldLayer :
CCTintTo* tint1 = [CCTintTo actionWithDuration:2 red:255 green:0 blue:0];
CCTintTo* tint2 = [CCTintTo actionWithDuration:2 red:0 green:0 blue:255];
....
CCSequence* sequence = [CCSequence actions:tint1, tint2, nil];
[label runAction:sequence];
I tried to make the label change color forever but got stucked:
I don't know where to place the relavant commands+ dealing with the integers x,y,z
I tried to do the randomize process at the update method,but didn't have any access to the label, any ideas?
// HelloWorldLayer.h
// Essentials
//
// Created by Steffen Itterheim on 14.07.10.
// Copyright Steffen Itterheim 2010. All rights reserved.
//
#import "cocos2d.h"
#interface HelloWorld : CCLayer
{
CCTintTo* tint1;
CCSequence* sequence1;
// CCLabelTTF* label; even tried property
}
// returns a Scene that contains the HelloWorld as the only child
+(id) scene;
#end
//
// HelloWorldLayer.m
// Essentials
//
// Created by Steffen Itterheim on 14.07.10.
// Copyright Steffen Itterheim 2010. All rights reserved.
//
#import "HelloWorldScene.h"
#import "MenuScene.h"
integer_t x;
integer_t y;
integer_t z;
#implementation HelloWorld
+(id) scene
{
CCScene* scene = [CCScene node];
CCLayer* layer = [HelloWorld node];
[scene addChild:layer];
return scene;
}
-(id) init
{
if ((self = [super init]))
{
CCLOG(#"init %#", self);
// enable touch input
self.isTouchEnabled = YES;
CGSize size = [[CCDirector sharedDirector] winSize];
// add the "touch to continue" label
CCLabelTTF* label = [CCLabelTTF labelWithString:#"Touch Screen For Awesome" fontName:#"AmericanTypewriter-Bold" fontSize:30];
label.position = CGPointMake(size.width / 2, size.height / 8);
[self addChild:label];
[self schedule:#selector(update:) interval:1/60.0f];
/*
tint1 = [CCTintTo actionWithDuration:2 red:x green:y blue:z];
sequence1 = [CCSequence actions:tint1, nil ];
id goaction=[CCRepeatForever actionWithAction:sequence1];
[label runAction:goaction];
*/
}
return self;
}
-(void) registerWithTouchDispatcher
{
// call the base implementation (default touch handler)
[super registerWithTouchDispatcher];
//[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INT_MIN+1 swallowsTouches:YES];
}
-(void) update:(ccTime)delta
{
x=(integer_t )(CCRANDOM_0_1()*255); y=(integer_t )(CCRANDOM_0_1()*255); z=(integer_t )(CCRANDOM_0_1()*255);
tint1 = [CCTintTo actionWithDuration:2 red:x green:y blue:z ];
sequence1 = [CCSequence actions:tint1, nil ];
[HelloWorld.label runAction:goaction]; //property label not found on object of type 'HelloWorld'
}
// Touch Input Events
-(CGPoint) locationFromTouches:(NSSet *)touches
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView: [touch view]];
return [[CCDirector sharedDirector] convertToGL:touchLocation];
}
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
}
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint location = [self locationFromTouches:touches];
CCLOG(#"touch moved to: %.0f, %.0f", location.x, location.y);
}
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// the scene we want to see next
CCScene* scene = [MenuScene scene];
CCTransitionSlideInR* transitionScene = [CCTransitionSlideInR transitionWithDuration:3 scene:scene];
[[CCDirector sharedDirector] replaceScene:transitionScene];
}
-(void) ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
}
-(void) dealloc
{
CCLOG(#"dealloc: %#", self);
// always call [super dealloc] at the end of every dealloc method
[super dealloc];
}
#end
If you want the tint color to be random for each time, then you cannot use CCTintTo directly inside CCRepeatForever. You need to re-randomize the RGB values for each CCTintTo action. Thus you need to embed the randomization process inside the action by using block. Here is how:
// do this in init method
__block void (^changeTint)(CCNode*) = [[^(CCNode *node) {
GLubyte x = (integer_t)(CCRANDOM_0_1()*255), y = (integer_t)(CCRANDOM_0_1()*255), z = (integer_t)(CCRANDOM_0_1()*255);
[node runAction:[CCSequence actionOne:[CCTintTo actionWithDuration:2 red:x green:y blue:z]
two:[CCCallBlockN actionWithBlock:changeTint]]];
} copy] autorelease];
changeTint(label);
You should look at CCRepeatForever action. As the name implies, it will repeat the action it points to forever. So you should remove your update method where you are changing the colors, and return to the CCSequence code that you had, and embed that in a CCRepeatForever action:
CCTintTo* tint1 = [CCTintTo actionWithDuration:2 red:255 green:0 blue:0];
CCTintTo* tint2 = [CCTintTo actionWithDuration:2 red:0 green:0 blue:255];
....
CCSequence* sequence = [CCSequence actions:tint1, tint2, nil];
CCAction* repeat = [CCRepeatForever actionWithAction:sequence];
[label runAction:repeat];

Can I add custom UI Elements to UIActionSheet?

I've successfully added Buttons to my UIActionSheet. I was wondering if I could add other elements, adjust the opacity, and alter the direction of the panel flying in (default comes in from below)with my UIActionSheet?
I am relatively new to iOS programming so any help would be greatly appreciated.
If you’re going to customize it to that degree, you’re better off just creating your own custom overlay view and adding whatever controls you need to it. Adjusting the animation direction in particular would be more trouble than it’s worth.
For more information on custom views and the view hierarchy, plus a useful section on animations (see the sidebar), check out the View Programming Guide for iOS.
Write implemention!
//.h
#import <UIKit/UIKit.h>
#interface UIImageActionSheet : UIActionSheet {
UIImage *titleImage;
}
-(id) initWithImage:(UIImage *)image
title:(NSString *)title
delegate:(id <UIActionSheetDelegate>)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles;
#end
//.m file
#import "UIImageActionSheet.h"
#implementation UIImageActionSheet
-(id) initWithImage:(UIImage *)image
title:(NSString *)title
delegate:(id <UIActionSheetDelegate>)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles{
self = [super initWithTitle:title delegate:delegate
cancelButtonTitle:cancelButtonTitle
destructiveButtonTitle:destructiveButtonTitle
otherButtonTitles:otherButtonTitles,nil];
if (self) {
titleImage=image;
[titleImage retain];
UIImageView *imageView = [[UIImageView alloc] initWithImage:titleImage];
imageView.frame = CGRectZero;
for (UIView *subView in self.subviews){
if (![subView isKindOfClass:[UILabel class]]) {
[self insertSubview:imageView aboveSubview:subView];
break;
}
}
[imageView release];
}
return self;
}
- (CGFloat) maxLabelYCoordinate {
// Determine maximum y-coordinate of labels
CGFloat maxY = 0;
for( UIView *view in self.subviews ){
if([view isKindOfClass:[UILabel class]]) {
CGRect viewFrame = [view frame];
CGFloat lowerY = viewFrame.origin.y + viewFrame.size.height;
if(lowerY > maxY)
maxY = lowerY;
}
}
return maxY;
}
-(void) layoutSubviews{
[super layoutSubviews];
CGRect frame = [self frame];
CGFloat labelMaxY = [self maxLabelYCoordinate];
for(UIView *view in self.subviews){
if (![view isKindOfClass:[UILabel class]]) {
if([view isKindOfClass:[UIImageView class]]){
CGRect viewFrame = CGRectMake((320 - titleImage.size.width)/2, labelMaxY + 10,
titleImage.size.width, titleImage.size.height);
[view setFrame:viewFrame];
}
else if(![view isKindOfClass:[UIImageView class]]) {
CGRect viewFrame = [view frame];
viewFrame.origin.y += titleImage.size.height+10;
[view setFrame:viewFrame];
}
}
}
frame.origin.y -= titleImage.size.height + 2.0;
frame.size.height += titleImage.size.height + 2.0;
[self setFrame:frame];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code.
}
*/
- (void)dealloc {
[super dealloc];
if (titleImage) {
[titleImage release];
}
}
#end
You have to create a custom overlay