iOS Quartz Changing stroke color - objective-c

I am new to iOS and am doing this as a learning experience. I got most of this code from a tutorial and its working but I wanted to add more stroke colors. My code begins with a default stroke in UIColor greenColor, but I have two buttons labeled "Red" and "Blue" that should change the stroke color to Red or Blue when pressed. I want to press Red, then start drawing and have that stroke come out red, etc. like in MS Paint. I've confirmed my UIButtons are linked up correctly. Any help is appreciated, thanks!
DrawView.h:
#import <UIKit/UIKit.h>
#interface DrawView : UIImageView
- (void)changeOption:(NSString *)withOption;
#end
DrawView.m:
#import "DrawView.h"
#interface DrawView()
#property (nonatomic) BOOL fingerMoved;
#property (nonatomic) CGPoint lastPoint;
#end
#implementation DrawView
CGFloat red = 0.0, green = 0.0, blue = 0.0, width = 5.0;
#synthesize fingerMoved = _fingerMoved;
#synthesize lastPoint = _lastPoint;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)changeOption:(NSString *)withOption
{
if ([withOption isEqualToString:#"Black"]) {
red = 0.0; green = 0.0; blue = 0.0; width = 5.0;
}else if ([withOption isEqualToString:#"Red"]) {
red = 1.0; green = 0.0; blue = 0.0; width = 5.0;
}else if ([withOption isEqualToString:#"Blue"]) {
red = 0.0; green = 0.0; blue = 1.0; width = 5.0;
}else if ([withOption isEqualToString:#"Green"]) {
red = 0.0; green = 1.0; blue = 0.0; width = 5.0;
}else if ([withOption isEqualToString:#"Brown"]) {
red = 0.4; green = 0.0; blue = 0.0; width = 5.0;
}else if ([withOption isEqualToString:#"Orange"]) {
red = 1.0; green = 0.6; blue = 0.0; width = 5.0;
}else if ([withOption isEqualToString:#"Yellow"]) {
red = 1.0; green = 1.0; blue = 0.0; width = 5.0;
}else if ([withOption isEqualToString:#"Purple"]) {
red = 0.5; green = 0.0; blue = 1.0; width = 5.0;
}else if ([withOption isEqualToString:#"Eraser"]) {
red = 1.0; green = 1.0; blue = 1.0; width = 13.0;
}else if ([withOption isEqualToString:#"Clear"]) {
self.image = nil;
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.fingerMoved = NO;
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2) {
self.image = nil;
return;
}
self.lastPoint = [touch locationInView:self];
self.lastPoint = CGPointMake(self.lastPoint.x, self.lastPoint.y - 20);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
self.fingerMoved = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self];
currentPoint.y -= 20;
UIGraphicsBeginImageContext(self.frame.size);
[self.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), width);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), self.lastPoint.x, self.lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.lastPoint = currentPoint;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2) {
self.image = nil;
return;
}
if (!self.fingerMoved) {
UIGraphicsBeginImageContext(self.frame.size);
[self.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), width);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), self.lastPoint.x, self.lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), self.lastPoint.x, self.lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end

Silly mistake in some other code. Fixed now.

Related

SprikeKit physics - How can i make my character stand up after falling down?

I'm new to sprite kit and game physics in general. I want my character to stand up upright whenever he falls over or knocked down. A bit like a floor-mounted punch bag. Here's my current code:
#import "MyScene.h"
#interface MyScene () <SKPhysicsContactDelegate> {
SKSpriteNode *_body;
SKSpriteNode *_leg1;
SKSpriteNode *_leg2;
SKSpriteNode *_foot1;
SKSpriteNode *_foot2;
}
#end
#implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
//self.backgroundColor = [SKColor greenColor];
self.physicsWorld.gravity = CGVectorMake(0, -2.0);
self.physicsWorld.contactDelegate = self;
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
SKSpriteNode *button = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(50, 50)];
button.position = CGPointMake(40, 40);
button.zPosition = 10;
button.name = #"button";
[self addChild: button];
[self createCharacter];
}
return self;
}
-(void)createCharacter {
// Add sprites
_body = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(40, 60)];
_body.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild: _body];
_leg1 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(14, 60)];
_leg1.position = CGPointMake(_body.position.x+20-7, _body.position.y-65);
[self addChild:_leg1];
_foot1 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(20, 10)];
_foot1.position = CGPointMake(_leg1.position.x-2.5, _leg1.position.y-40);
[self addChild:_foot1];
_leg2 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(14, 60)];
_leg2.position = CGPointMake(_body.position.x-20+7, _body.position.y-65);
[self addChild:_leg2];
_foot2 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(20, 10)];
_foot2.position = CGPointMake(_leg2.position.x-2.5, _leg2.position.y-40);
[self addChild:_foot2];
// Add physics bodies to sprites
_body.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_body.size];
_leg1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_leg1.size];
_foot1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_foot1.size];
_foot1.physicsBody.mass = 1;
_leg2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_leg2.size];
_foot2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_foot2.size];
_foot2.physicsBody.mass = 0.5;
// Add joints
SKPhysicsJoint *hipJoint = [SKPhysicsJointFixed jointWithBodyA:_body.physicsBody bodyB:_leg1.physicsBody anchor:_leg1.position];
SKPhysicsJoint *ankleJoint = [SKPhysicsJointFixed jointWithBodyA:_leg1.physicsBody bodyB:_foot1.physicsBody anchor:_foot1.position];
SKPhysicsJointPin *hipJoint2 = [SKPhysicsJointPin jointWithBodyA:_body.physicsBody bodyB:_leg2.physicsBody anchor:CGPointMake(_leg2.position.x, CGRectGetMaxY(_leg2.frame))];
[hipJoint2 setShouldEnableLimits:YES];
[hipJoint2 setLowerAngleLimit:-M_PI_2];
[hipJoint2 setUpperAngleLimit:0.0];
SKPhysicsJoint *ankleJoint2 = [SKPhysicsJointFixed jointWithBodyA:_leg2.physicsBody bodyB:_foot2.physicsBody anchor:_foot2.position];
[self.scene.physicsWorld addJoint:hipJoint];
[self.scene.physicsWorld addJoint:ankleJoint];
[self.scene.physicsWorld addJoint:hipJoint2];
[self.scene.physicsWorld addJoint:ankleJoint2];
}
-(void)characterJump {
CGFloat radianFactor = 0.0174532925;
CGFloat rotationInDegrees = _body.zRotation / radianFactor;
CGFloat newRotationDegrees = rotationInDegrees + 90;
CGFloat newRotationRadians = newRotationDegrees * radianFactor;
CGFloat r = 500;
CGFloat dx = r * cos(newRotationRadians);
CGFloat dy = r * sin(newRotationRadians);
[_body.physicsBody applyImpulse:CGVectorMake(dx, dy)];
NSLog(#"leg2 rotation: %f", _foot2.zRotation / radianFactor);
}
-(void)characterKick {
NSLog(#"Kick..");
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"button"]) {
[self characterJump];
[self characterKick];
}
}
-(void)update:(CFTimeInterval)currentTime {
}
#end
Run the code and tap the button to make him jump and eventually fall over. Also, the joint limits don't work as it breaks through the limits sometimes.
Help would be really appreciated.
I resolved this issue by checking the _body SKSpriteNode's 'y' position in the scene's update method. If the 'y' position was below a certain limit, I applied an impulse to the body's physicsBody from below to stand it up again.
This worked as required/desired.
-(void)update:(CFTimeInterval)currentTime {
if(_body.position.y < 30) {
[self upOnYourFeet];
}
}
-(void)upOnYourFeet {
[_body.physicsBody applyImpulse:CGVectorMake(0, 80)];
}

Bounce UIImageView back when dragged off screen

What I need is when a UIImageView is dragged off of the screen it to bounce back when it gets let go. I have it working in the left and top sides this is what I am doing.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (!CGRectContainsPoint(self.view.frame, imageView.frame.origin)){
CGFloat newX = 0.0f;
CGFloat newY = 0.0f;
// If off screen upper and left
if (imageView.frame.origin.x < 0.0f){
CGFloat negX = imageView.frame.origin.x * -1;
newX = negX;
}else{
newX = imageView.frame.origin.x;
}
if (imageView.frame.origin.y < 0.0f){
CGFloat negY = imageView.frame.origin.y * -1;
newY = negY;
}else{
newY = imageView.frame.origin.y;
}
CGRect newPoint = CGRectMake(newX, newY, imageView.frame.size.width, imageView.frame.size.height);
[UIView beginAnimations:#"BounceAnimations" context:nil];
[UIView setAnimationDuration:.5];
[letterOutOfBounds play];
[imageView setFrame:newPoint];
[UIView commitAnimations];
}
}
}
So I would like to achieve the same thing for the right and bottom sides. But I have been stuck at this for awhile. Any Ideas?
How about something like the following?
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UIImageView *imageView = nil;
BOOL moved = NO;
CGRect newPoint = imageView.frame;
// If off screen left
if (newPoint.origin.x < 0.0f){
newPoint.origin.x *= -1.0;
moved = YES;
}
// if off screen up
if (newPoint.origin.y < 0.0f){
newPoint.origin.y *= -1.0;
moved = YES;
}
// if off screen right
CGFloat howFarOffRight = (newPoint.origin.x + newPoint.size.width) - imageView.superview.frame.size.width;
if (howFarOffRight > 0.0)
{
newPoint.origin.x -= howFarOffRight * 2;
moved = YES;
}
// if off screen bottom
CGFloat howFarOffBottom = (newPoint.origin.y + newPoint.size.height) - imageView.superview.frame.size.height;
if (howFarOffBottom > 0.0)
{
newPoint.origin.y -= howFarOffBottom * 2;
moved = YES;
}
if (moved)
{
[UIView beginAnimations:#"BounceAnimations" context:nil];
[UIView setAnimationDuration:.5];
[letterOutOfBounds play];
[imageView setFrame:newPoint];
[UIView commitAnimations];
}
}
As I read your code, the logic of "if off the left side, move it back on to the view by the same distance it was off the screen." To be honest, that doesn't quite make sense to me (why, when bouncing back, does the coordinate depend upon how far off the screen it was), but I've tried to honor that in the "off screen right" and "off screen bottom" logic. Obviously my logic is using the superview of imageView to determine the width of the containing view, but if that's not appropriate, replace it with whatever is.
Edit:
I personally do this stuff with gesture recognizers, such as:
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[self.imageView addGestureRecognizer:pan];
self.imageView.userInteractionEnabled = YES;
Thus, a gesture recognizer to animate moving the image back would be:
- (void)handlePan:(UIPanGestureRecognizer *)gesture
{
static CGRect originalFrame; // you could make this an ivar if you want, but just for demonstration purposes
if (gesture.state == UIGestureRecognizerStateBegan)
{
originalFrame = self.imageView.frame;
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
CGPoint translate = [gesture translationInView:gesture.view];
CGRect newFrame = originalFrame;
newFrame.origin.x += translate.x;
newFrame.origin.y += translate.y;
gesture.view.frame = newFrame;
}
else if (gesture.state == UIGestureRecognizerStateEnded || gesture.state == UIGestureRecognizerStateCancelled)
{
CGRect newFrame = gesture.view.frame;
newFrame.origin.x = fmaxf(newFrame.origin.x, 0.0);
newFrame.origin.x = fminf(newFrame.origin.x, gesture.view.superview.bounds.size.width - newFrame.size.width);
newFrame.origin.y = fmaxf(newFrame.origin.y, 0.0);
newFrame.origin.y = fminf(newFrame.origin.y, gesture.view.superview.bounds.size.height - newFrame.size.height);
// animate how ever you want ... I generally just do animateWithDuration
[UIView animateWithDuration:0.5 animations:^{
gesture.view.frame = newFrame;
}];
}
}
Or, if you want a gesture recognizer that just prevents the dragging of the image off the screen in the first place, it would be:
- (void)handlePan:(UIPanGestureRecognizer *)gesture
{
static CGRect originalFrame;
if (gesture.state == UIGestureRecognizerStateBegan)
{
originalFrame = self.imageView.frame;
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
CGPoint translate = [gesture translationInView:gesture.view];
CGRect newFrame = originalFrame;
newFrame.origin.x += translate.x;
newFrame.origin.x = fmaxf(newFrame.origin.x, 0.0);
newFrame.origin.x = fminf(newFrame.origin.x, gesture.view.superview.bounds.size.width - newFrame.size.width);
newFrame.origin.y += translate.y;
newFrame.origin.y = fmaxf(newFrame.origin.y, 0.0);
newFrame.origin.y = fminf(newFrame.origin.y, gesture.view.superview.bounds.size.height - newFrame.size.height);
gesture.view.frame = newFrame;
}
}
By the way, in iOS 7, you can give the animation of the image view back to its original location a little bounciness by using the new animationWithDuration with the usingSpringWithDampening and initialSpringVelocity parameters:
[UIView animateWithDuration:1.0
delay:0.0
usingSpringWithDamping:0.3
initialSpringVelocity:0.1
options:0
animations:^{
// set the new `frame` (or update the constraint constant values that
// will dictate the `frame` and call `layoutViewsIfNeeded`)
}
completion:nil];
Alternatively, in iOS7, you can also use UIKit Dynamics to add a UISnapBehavior:
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
self.animator.delegate = self;
UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:self.viewToAnimate snapToPoint:CGPointMake(self.viewToAnimate.center.x, self.view.frame.size.height - 50)];
// optionally, you can control how much bouncing happens when it finishes, e.g., for a lot of bouncing:
//
// snap.damping = 0.2;
// you can also slow down the snap by adding some resistance
//
// UIDynamicItemBehavior *resistance = [[UIDynamicItemBehavior alloc] initWithItems:#[self.viewToAnimate]];
// resistance.resistance = 20.0;
// resistance.angularResistance = 200.0;
// [self.animator addBehavior:resistance];
[self.animator addBehavior:snap];
I think the easiest way is to check whether your imageView has gone out of your self.view.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (!CGRectContainsRect(self.view.frame, imageView.frame)){
// Your animation to bounce.
}
}

Line Drawing in iOS

How to Draw a straight line in iOS irrespective of how user draws it.
I want the line to be of the length of number of pixels user drags his finger.
But it needs to be either vertical or horizontal based on whether user slides his finger from left to right of the screen or top to bottom of the screen.
Lines should not be slanting or any other shape. It needs to be straight.
I have gone through articles which says "Open GL" is the only way.
I have tried coding it myself but when I change the direction from vertical to horizontal or vice versa, I get some extra line or gap between where horizontal line ends and where vertical line starts:
In header file:
#interface ViewController : UIViewController
{
BOOL mouseSwiped;
CGPoint lastPoint;
CGPoint previousPoint;
UIBezierPath *currentPath;
CGFloat lastPointY;
CGFloat lastPointX;
BOOL xchanging;
BOOL ychanging;
NSMutableArray *arrayTouch;
}
#property (weak, nonatomic) IBOutlet UIImageView *drawImage;
#property UIBezierPath *currentPath;
#end
In implementation file:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = NO;
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2) {
drawImage.image = nil;
[arrayTouch removeAllObjects];
return;
}
lastPoint = [touch locationInView:self.view];
[arrayTouch addObject:touch];
lastPointY = lastPoint.y;
lastPointX = lastPoint.x;
lastPoint.y -= 1;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
currentPoint.y -= 1;
int currentPointXVal = currentPoint.x;
int currentPointYVal = currentPoint.y;
int lastPointXVal = lastPoint.x;
int lastPointYVal = lastPoint.y;
int diffX = abs(currentPointXVal - lastPointXVal);
int diffY = abs(currentPointYVal - lastPointYVal);
if(currentPoint.x > lastPoint.x && diffX > diffY)
{
if(ychanging == YES)
{
lastPointY = currentPoint.y;
lastPointX = currentPoint.x;
ychanging = NO;
}
xchanging = YES;
NSLog(#"x increasing");
NSLog(#"currentPoint: %#",NSStringFromCGPoint(currentPoint));
NSLog(#"lastPoint: %#",NSStringFromCGPoint(lastPoint));
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPointY);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, lastPointY);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
if(currentPoint.y > lastPoint.y && diffY > diffX)
{
if(xchanging == YES)
{
lastPointY = currentPoint.y;
lastPointX = currentPoint.x;
xchanging = NO;
}
ychanging = YES;
NSLog(#"y increasing");
NSLog(#"currentPoint: %#",NSStringFromCGPoint(currentPoint));
NSLog(#"lastPoint: %#",NSStringFromCGPoint(lastPoint));
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPointX, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPointX, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
if(currentPoint.x < lastPoint.x && diffX > diffY)
{
if(ychanging == YES)
{
lastPointY = currentPoint.y;
lastPointX = currentPoint.x;
ychanging = NO;
}
xchanging = YES;
NSLog(#"x decreasing");
NSLog(#"currentPoint: %#",NSStringFromCGPoint(currentPoint));
NSLog(#"lastPoint: %#",NSStringFromCGPoint(lastPoint));
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPointY);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, lastPointY);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
if(currentPoint.y < lastPoint.y && diffY > diffX)
{
if(xchanging == YES)
{
lastPointY = currentPoint.y;
lastPointX = currentPoint.x;
xchanging = NO;
}
ychanging = YES;
NSLog(#"y decreasing");
NSLog(#"currentPoint: %#",NSStringFromCGPoint(currentPoint));
NSLog(#"lastPoint: %#",NSStringFromCGPoint(lastPoint));
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPointX, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPointX, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
lastPoint = currentPoint;
}
Is there any way I can do it without Open GL?
Sure - You can do this, just take away the slope from the line:
#implementation LineDrawingView
{
CGPoint touchStart;
CGPoint touchCurrent;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
touchStart = (CGPoint) { -1, -1 };
touchCurrent = (CGPoint) { -1, -1 };
}
return self;
}
- (void)drawRect:(CGRect)rect
{
if (touchStart.x != -1)
{
// calculate the line rotation
enum { horizontal, vertical } lineRot = horizontal;
if (touchStart.y == touchCurrent.y)
{
// straight line
lineRot = horizontal;
}
else
{
// calculate the slope
double slope = fabs((touchCurrent.y - touchStart.y) / (touchCurrent.x - touchStart.x));
if (slope > 1)
lineRot = vertical;
}
// draw the actual line
CGPoint lineEndPoint = { };
if (lineRot == horizontal)
lineEndPoint = (CGPoint) { touchCurrent.x, touchStart.y }; // horizontal line
else
lineEndPoint = (CGPoint) { touchStart.x, touchCurrent.y }; // vertical line
// actually draw the line
[[UIColor redColor] setStroke];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:touchStart];
[path addLineToPoint:lineEndPoint];
[path stroke];
}
}
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
touchStart = [[touches anyObject] locationInView:self];
touchCurrent = touchStart;
[self setNeedsDisplay];
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
touchCurrent = [[touches anyObject] locationInView:self];
[self setNeedsDisplay];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
touchStart = touchCurrent = (CGPoint) { -1, -1 };
[self setNeedsDisplay];
}
#end
You can extend this to use an array of lines if you'd like, this is just a simple explanation.

ios Help Screen semi-transparent overlay

Wondering if anyone can shed some light on how to create a semi-transparent Help screen on an ipad or iphone app? Something similar to Googles app.
I have a splitViewController and I want to overlay a see-through black overlay on top of the splitViewController where I can show Help information about each item you can click in the splitViewController.
I followed http://cocoawithlove.com/2009/04/showing-message-over-iphone-keyboard.html which gets me the overlay, but I am now adding clickable UIViews (eg a close button to dismiss the overlay). The issue is when I setup touchesEnded:withEvent I cannot seem to convert clicks from the main LoadingView to closeButton to see what was actually clicked?
See the touches ended at the end of the code
================================================================
#import "HelpView.h"
#import <QuartzCore/QuartzCore.h>
//
CGPathRef NewPathWithRoundRect(CGRect rect, CGFloat cornerRadius)
{
//
// Create the boundary path
//
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL,
rect.origin.x,
rect.origin.y + rect.size.height - cornerRadius);
// Top left corner
CGPathAddArcToPoint(path, NULL,
rect.origin.x,
rect.origin.y,
rect.origin.x + rect.size.width,
rect.origin.y,
cornerRadius);
// Top right corner
CGPathAddArcToPoint(path, NULL,
rect.origin.x + rect.size.width,
rect.origin.y,
rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height,
cornerRadius);
// Bottom right corner
CGPathAddArcToPoint(path, NULL,
rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height,
rect.origin.x,
rect.origin.y + rect.size.height,
cornerRadius);
// Bottom left corner
CGPathAddArcToPoint(path, NULL,
rect.origin.x,
rect.origin.y + rect.size.height,
rect.origin.x,
rect.origin.y,
cornerRadius);
// Close the path at the rounded rect
CGPathCloseSubpath(path);
return path;
}
#implementation HelpView
#synthesize closeButton = _closeButton;
- (id)loadingViewInView:(UIView *)aSuperview
{
HelpView *loadingView =
[[HelpView alloc] initWithFrame:[aSuperview bounds]];
if (!loadingView)
{
return nil;
}
loadingView.opaque = NO;
loadingView.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[aSuperview addSubview:loadingView];
const CGFloat DEFAULT_LABEL_WIDTH = 100.0;
const CGFloat DEFAULT_LABEL_HEIGHT = 40.0;
CGRect labelFrame = CGRectMake(0, 0, DEFAULT_LABEL_WIDTH, DEFAULT_LABEL_HEIGHT);
UILabel *loadingLabel = [[UILabel alloc] initWithFrame:labelFrame];
loadingLabel.text = NSLocalizedString(#"Close", nil);
loadingLabel.textColor = [UIColor whiteColor];
loadingLabel.backgroundColor = [UIColor clearColor];
loadingLabel.textAlignment = UITextAlignmentCenter;
loadingLabel.font = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];
loadingLabel.autoresizingMask =
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleBottomMargin;
// Background for Close button
CALayer *closeButtonBackground = [CALayer layer];
closeButtonBackground.opacity = 0.3;
closeButtonBackground.borderColor = [UIColor whiteColor].CGColor;
closeButtonBackground.borderWidth = 2.0;
closeButtonBackground.cornerRadius = 5.0;
closeButtonBackground.backgroundColor = [UIColor blackColor].CGColor;
// Finish setting up frame for Close button
labelFrame.origin.x = 0;
labelFrame.origin.y = 0;
loadingLabel.frame = labelFrame;
closeButtonBackground.frame = labelFrame;
CGRect viewRect = CGRectMake(loadingView.frame.size.width -150 ,loadingView.frame.size.height - 85,100,40);
self.closeButton = [[UIView alloc] initWithFrame:viewRect];
self.closeButton.userInteractionEnabled = YES;
self.userInteractionEnabled = NO;
[loadingView addSubview:self.closeButton];
[self.closeButton.layer addSublayer:closeButtonBackground];
[self.closeButton addSubview:loadingLabel];
// Set up the fade-in animation
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionFade];
[[aSuperview layer] addAnimation:animation forKey:#"layerAnimation"];
//[loadingView createGestureRecognizer];
return loadingView;
}
- (void)removeView
{
UIView *aSuperview = [self superview];
[super removeFromSuperview];
// Set up the animation
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionFade];
[[aSuperview layer] addAnimation:animation forKey:#"layerAnimation"];
}
- (void)drawRect:(CGRect)rect
{
rect.size.height -= 1;
rect.size.width -= 1;
const CGFloat RECT_PADDING = 0.0;
rect = CGRectInset(rect, RECT_PADDING, RECT_PADDING);
const CGFloat ROUND_RECT_CORNER_RADIUS = 0.0;
CGPathRef roundRectPath = NewPathWithRoundRect(rect, ROUND_RECT_CORNER_RADIUS);
CGContextRef context = UIGraphicsGetCurrentContext();
const CGFloat BACKGROUND_OPACITY = 0.85;
CGContextSetRGBFillColor(context, 0, 0, 0, BACKGROUND_OPACITY);
CGContextAddPath(context, roundRectPath);
CGContextFillPath(context);
const CGFloat STROKE_OPACITY = 0.25;
CGContextSetRGBStrokeColor(context, 1, 1, 1, STROKE_OPACITY);
CGContextAddPath(context, roundRectPath);
CGContextStrokePath(context);
CGPathRelease(roundRectPath);
}
- (void)handleSingleDoubleTap:(UITapGestureRecognizer *)sender {
NSLog(#"");
CGPoint tapPoint = [sender locationInView:sender.view];
CALayer* layerThatWasTapped = [self.layer hitTest:tapPoint];
CGPoint convertedPoint = [layerThatWasTapped convertPoint:layerThatWasTapped.position toLayer:self.closeButton.layer];
BOOL myBool = [self.closeButton.layer containsPoint:convertedPoint];
[UIView beginAnimations:nil context:NULL];
sender.view.center = tapPoint;
[UIView commitAnimations];
}
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView: self];
CGPoint convertedPoint = [self convertPoint:point toView:[self.closeButton superview]];
if (CGRectContainsPoint(self.closeButton.bounds, convertedPoint)) {
NSLog (#"YAY!");
}
} // touchesEnded
Solved this with NSNotifications. Something like this... its a little static... should be more dynamic.
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(eventHandler:)
name:#"SomeButtonClicked"
object:nil ];
-(void)eventHandler: (NSNotification *) notification
{
NSString *buttonWhichWasClicked = [[notification userInfo] objectForKey:#"buttonName"];
NSLog(#" %#", buttonWhichWasClicked);
if ([buttonWhichWasClicked isEqualToString:#"close"]){
[self removeView];
}
//Tell other buttons to dim/remove themselves as a new one was selected
}
- (void)removeView
{
//code to remove view
}

iPhone trim audio recording

I have a voice memo component in my app, and I want to allow the user to trim the audio, similar to QuickTime X on Mac OS Ten point Six handles it, or like the Voice Memos app on the iPhone. Here's an example of both:
Any help is appreciated.
I am not a UI programmer by any means. This was a test I wrote to see how to write custom controls. This code may or may not work. I have not touched it in some time.
header
#interface SUIMaxSlider : UIControl {
#private
float_t minimumValue;
float_t maximumValue;
float_t value;
CGPoint trackPoint;
}
#property (nonatomic, assign) float_t minimumValue, maximumValue;
#property (nonatomic, assign) float_t value;
#end
implementation
#import "SUIMaxSlider.h"
#import <CoreGraphics/CoreGraphics.h>
#import <QuartzCore/QuartzCore.h>
//#import "Common.h"
#define kSliderPadding 5
#implementation SUIMaxSlider
#synthesize minimumValue, maximumValue;
#pragma mark -
#pragma mark Interface Initialization
- (id) initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
trackPoint.x = self.bounds.size.width;
self.backgroundColor = [UIColor colorWithRed:135.0/255.0 green:173.0/255.0 blue:255.0/255.0 alpha:0.0];
}
return self;
}
- (id) initWithFrame: (CGRect) aFrame {
if (self = [super initWithFrame:aFrame]) {
self.frame = aFrame;
self.bounds = aFrame;
self.center = CGPointMake(CGRectGetMidX(aFrame), CGRectGetMidY(aFrame));
trackPoint.x = aFrame.size.width;
}
return self;
}
- (id) init {
return [self initWithFrame:CGRectZero];
}
#pragma mark -
#pragma mark Properties.
#pragma mark -
- (float_t) value {
return value;
}
- (void) setValue:(float_t) v {
value = fmin(v, maximumValue);
value = fmax(value, minimumValue);
float_t delta = maximumValue - minimumValue;
float_t scalar = ((self.bounds.size.width - 2 * kSliderPadding) / delta) ;
float_t x = (value - minimumValue) * scalar;
x += 5.0;
trackPoint.x = x;
[self setNeedsDisplay];
}
#pragma mark -
#pragma mark Interface Drawing
#pragma mark -
- (void) drawRect:(CGRect) rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef lightBlue = [UIColor colorWithRed:135.0/255.0 green:173.0/255.0 blue:255.0/255.0 alpha:1.0].CGColor;
CGColorRef lightBlueAlpha = [UIColor colorWithRed:135.0/255.0 green:173.0/255.0 blue:255.0/255.0 alpha:0.7].CGColor;
CGColorRef lightGrayColor = [UIColor colorWithRed:130.0/255.0 green:130.0/255.0 blue:130.0/255.0 alpha:1.0].CGColor;
CGColorRef darkGrayColor = [UIColor colorWithRed:70.0/255.0 green:70.0/255.0 blue:70.0/255.0 alpha:1.0].CGColor;
CGColorRef redColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.6].CGColor;
CGRect boundsRect = self.bounds;
CGRect sliderRect = CGRectMake(0, 0, boundsRect.size.width, boundsRect.size.height / 2);
/*
CGContextSetFillColorWithColor(context, lightGrayColor);
CGContextFillRect(context, sliderRect);
halfHeight.origin.y = sliderRect.size.height;
CGContextSetFillColorWithColor(context, darkGrayColor);
CGContextFillRect(context, sliderRect);
*/
CGFloat tx = fmin(sliderRect.size.width - kSliderPadding, trackPoint.x);
tx = fmax(kSliderPadding, tx);
sliderRect.origin.y = boundsRect.origin.y;
sliderRect.size.width = tx ;
CGContextSetFillColorWithColor(context, lightBlueAlpha);
CGContextFillRect(context, sliderRect);
sliderRect.origin.y = sliderRect.size.height;
CGContextSetFillColorWithColor(context, lightBlue);
CGContextFillRect(context, sliderRect);
CGFloat mid = boundsRect.size.height / 2 ;
CGPoint a = CGPointMake(tx - kSliderPadding, mid);
CGPoint b = CGPointMake(tx, mid - kSliderPadding);
CGPoint c = CGPointMake(tx + kSliderPadding, mid);
CGPoint d = CGPointMake(tx, mid + kSliderPadding);
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetLineWidth(context, 2.0);
CGContextBeginPath(context);
CGContextMoveToPoint(context, a.x, a.y);
CGContextAddLineToPoint(context, b.x, b.y);
CGContextAddLineToPoint(context, c.x, c.y);
CGContextAddLineToPoint(context, d.x, d.y);
CGContextAddLineToPoint(context, a.x, a.y);
CGContextFillPath(context);
}
#pragma mark -
#pragma mark Touch Tracking
#pragma mark -
- (void) trackTouch:(UITouch *) touch {
CGPoint p = [touch locationInView:self];
//bound track point
trackPoint.x = fmax(p.x, kSliderPadding) ;
trackPoint.x = fmin(trackPoint.x, self.bounds.size.width - kSliderPadding);
[self setNeedsDisplay];
float_t x = trackPoint.x - kSliderPadding;
float_t delta = maximumValue - minimumValue;
float_t scalar = (x / (self.bounds.size.width - 2 * kSliderPadding)) ;
value = minimumValue + (delta * scalar);
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
[self trackTouch:touch];
}
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint p = [touch locationInView:self];
trackPoint.x = fmax(p.x, kSliderPadding) ;
trackPoint.x = fmin(trackPoint.x, self.bounds.size.width - kSliderPadding);
[self setNeedsDisplay];
return YES;
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
[self trackTouch:touch];
return YES;
}
#end