I have a Sprite object defined as follows:
#interface Sprite : NSObject {
CGFloat x; // x location
CGFloat y; // y location
CGFloat r; // red tint
CGFloat g; // green tint
CGFloat b; // blue tint
CGFloat alpha; // alpha value, for transparency
}
In the initWithCoder function of the containing view i instanciated it using:
sprite = [[Sprite alloc] init];
sprite.x = 50;
sprite.y = 100;
sprite.width = 100;
sprite.height = 200;
sprite.r = 0.0;
sprite.g = 1.0;
sprite.b = 0.0;
and I correctly see a green rectangle.
Now I would like to move it. I defined a moveTo method like this
- (void) moveTo: (CGPoint) p
{
x = p.x;
y = p.y;
}
But when I call it nothing happens. I don't know how to redraw my object.
How do you see a green rect? where do you draw it? NSObject cannot draw...
You could derive it from a UIView and change your moveTo to be like this:
- (void) moveTo: (CGPoint) p
{
self.frame.origin = p;
[self setNeedsDisplay];
}
NSObject aren't drawable objects. If you want to have a drawable object you should use UIView or its subclass that have all methods for drawing itself like drawRect
Related
Well I made a randomNumber Class, (for practice and) for calculating a random position on my screen for an object and it works properly, except for it sometimes puts the sprite out of the screen.The x and y coordinates are smaller the screen height and width. but it doesn't show it on the screen.
The whole program is just basically randomly placing instances of an object inside the screen.
randomNumber.h
#import <Foundation/Foundation.h>
#import <SpriteKit/SpriteKit.h>
#interface randomNumber : NSObject
-(int)randNumX:(int) max :(SKSpriteNode *) sprite;
-(int)randNumY:(int) max :(SKSpriteNode *) sprite;
#end
randomNumber.m
#import "randomNumber.h"
#implementation randomNumber
-(int)randNumX:(int) max :(SKSpriteNode *) sprite {
int _spriteW = sprite.frame.size.width;
int _random = (arc4random() % (max - _spriteW));
NSLog(#"The x value is %d", _random);
return _random;
}
-(int)randNumY:(int) max :(SKSpriteNode *) sprite {
int _spriteH = sprite.frame.size.height;
int _random = (arc4random() % (max - _spriteH));
NSLog(#"The y value is %d", _random);
return _random;
}
#end
MyScene.m ( only the initilazeMole method )
-(void) initilazeMole {
int x = [self.rndNum randNumX:(self.scene.size.width):(self.mole)];
int y = [self.rndNum randNumY:(self.scene.size.height):(self.mole)]
self.mole = [SKSpriteNode spriteNodeWithImageNamed:#"spaceship"];
self.mole.anchorPoint = CGPointMake(0,0);
self.mole.position = CGPointMake(x,y);
SKAction *pulseRed = [SKAction sequence:#[
[SKAction colorizeWithColor:[SKColor redColor] colorBlendFactor:1.0 duration:0.5],
[SKAction waitForDuration:0.1],
[SKAction colorizeWithColorBlendFactor:0.0 duration:1.0]]];
[self.mole runAction: pulseRed];
NSLog(#"mole x position: %f", self.mole.position.x);
NSLog(#"mole y position: %f", self.mole.position.y);
[self addChild:self.mole];
}
I don't really understand why does it place it off the screen, hence I generate a random number that can maximally be ( the screen width - sprite width ) and ( the screen height - sprite height )
My project settings are set up for an iphone 3.5 inch in landscape mode.
Any idea where did my code go wrong ?
Try this:
- (CGPoint) randomPointWithinContainerSize:(CGSize)containerSize forViewSize:(CGSize)size {
NSLog(#"move");
CGFloat xRange = containerSize.width - size.width;
CGFloat yRange = containerSize.height - size.height;
CGFloat minX = (containerSize.width - xRange) / 2;
CGFloat minY = (containerSize.height - yRange) / 2;
int randomX = (arc4random() % (int)floorf(xRange)) + minX;
int randomY = (arc4random() % (int)floorf(yRange)) + minY;
return CGPointMake(randomX, randomY);
}
Then replace:
int x = [self.rndNum randNumX:(self.scene.size.width):(self.mole)];
int y = [self.rndNum randNumY:(self.scene.size.height):(self.mole)]
self.mole = [SKSpriteNode spriteNodeWithImageNamed:#"spaceship"];
self.mole.anchorPoint = CGPointMake(0,0);
self.mole.position = CGPointMake(x,y);
With:
self.mole.position = [self randomPointWithinContainerSize:self.scene.size forViewSize:self.mole.bounds.size];
I rotate my view with CGAffineTransform
[view setTransform:newTransform];
The frame values remain the same after transform is applied but how do I find "rotated" or transformed values of this frame?
(source: informit.com)
I want the exact coordinates of rotated frame edges, that is a, b, c, d points.
One thing to keep in mind is that the transform changes the coordinate system, so you will need to be able to convert between the parent 'view' and the child (transformed) view. Also, transforms preserve the center of the transformed object but not any of the other coordinates. So you need to calculate things in terms of the center. And there are several helpers you will need. (I got most of the following approach from Erica Sadun's book Core iOS Developer's Cookbook).
I usually add these as a category on UIView.
In order to transform the child's coordinates to those of the parent you need something like:
// helper to get pre transform frame
-(CGRect)originalFrame {
CGAffineTransform currentTransform = self.transform;
self.transform = CGAffineTransformIdentity;
CGRect originalFrame = self.frame;
self.transform = currentTransform;
return originalFrame;
}
// helper to get point offset from center
-(CGPoint)centerOffset:(CGPoint)thePoint {
return CGPointMake(thePoint.x - self.center.x, thePoint.y - self.center.y);
}
// helper to get point back relative to center
-(CGPoint)pointRelativeToCenter:(CGPoint)thePoint {
return CGPointMake(thePoint.x + self.center.x, thePoint.y + self.center.y);
}
// helper to get point relative to transformed coords
-(CGPoint)newPointInView:(CGPoint)thePoint {
// get offset from center
CGPoint offset = [self centerOffset:thePoint];
// get transformed point
CGPoint transformedPoint = CGPointApplyAffineTransform(offset, self.transform);
// make relative to center
return [self pointRelativeToCenter:transformedPoint];
}
// now get your corners
-(CGPoint)newTopLeft {
CGRect frame = [self originalFrame];
return [self newPointInView:frame.origin];
}
-(CGPoint)newTopRight {
CGRect frame = [self originalFrame];
CGPoint point = frame.origin;
point.x += frame.size.width;
return [self newPointInView:point];
}
-(CGPoint)newBottomLeft {
CGRect frame = [self originalFrame];
CGPoint point = frame.origin;
point.y += frame.size.height;
return [self newPointInView:point];
}
-(CGPoint)newBottomRight {
CGRect frame = [self originalFrame];
CGPoint point = frame.origin;
point.x += frame.size.width;
point.y += frame.size.height;
return [self newPointInView:point];
}
Swift 4
extension UIView {
/// Helper to get pre transform frame
var originalFrame: CGRect {
let currentTransform = transform
transform = .identity
let originalFrame = frame
transform = currentTransform
return originalFrame
}
/// Helper to get point offset from center
func centerOffset(_ point: CGPoint) -> CGPoint {
return CGPoint(x: point.x - center.x, y: point.y - center.y)
}
/// Helper to get point back relative to center
func pointRelativeToCenter(_ point: CGPoint) -> CGPoint {
return CGPoint(x: point.x + center.x, y: point.y + center.y)
}
/// Helper to get point relative to transformed coords
func newPointInView(_ point: CGPoint) -> CGPoint {
// get offset from center
let offset = centerOffset(point)
// get transformed point
let transformedPoint = offset.applying(transform)
// make relative to center
return pointRelativeToCenter(transformedPoint)
}
var newTopLeft: CGPoint {
return newPointInView(originalFrame.origin)
}
var newTopRight: CGPoint {
var point = originalFrame.origin
point.x += originalFrame.width
return newPointInView(point)
}
var newBottomLeft: CGPoint {
var point = originalFrame.origin
point.y += originalFrame.height
return newPointInView(point)
}
var newBottomRight: CGPoint {
var point = originalFrame.origin
point.x += originalFrame.width
point.y += originalFrame.height
return newPointInView(point)
}
}
You can find out the coordinates of the rotated view by using basic trigonometry. Here is how you can do it:
The first step is to know your view's width and height. Divide them by 2 and you get your triangle's adjacent and opposite sides (cyan and green respectively). In the example above width = 300 and height = 300. So adjacentSide = 150 and oppositeSice = 150.
Find the hypotenuse (red). For this you use the formula: h^2 = a^2 + b^2. After applying this formula we find the hypotenuse = 212.13
Find theta. This is the angle between the adjacentSide (cyan) and the hypotenuse (red). For this you use the formula cos(theta) = (h^2 + a^2 - o^2)/2*h*o. After applying this formula we find that theta = 0.785 (RADIANS). To convert this to degrees we apply the formula degrees = radians * 180 / PI = 45 (degrees). This is the initial (offset) angle of the hypotenuse. This is very important to realize. IF THE VIEW'S ROTATION OF YOUR VIEW IS ZERO THE HYPOTENUSE HAS AN OFFSET ANGLE OF 45(DEGREES). We're going to need theta shortly.
Now that we know the hypotenuse (red) we need the rotationAngle. In this example I used a UIRotationGestureRecognizer to rotate the square view. This class has a "rotation" property which tells us how much the view has rotated. This value is in RADIANS. In the example above the rotation is 0.3597 RADIANS. To convert it to degrees we use the formula degrees = radians * PI / 180. After applying the formula we find the rotation angle to be 20.61 degrees.
We can finally find the offset width (orange) and height (purple). For width we use the formula width = cos(rotationAngle - theta) * hypotenuse and for height we use the formula height = sen(rotationAngle - theta). WE HAVE TO SUBTRACT THETA (IN RADIANS!) FROM THE ROTATION ANGLE (IN RADIANS TOO!) BECAUSE THETA WAS THE INITIAL OFFSET. View it this way: the hypotenuse had an angle of 45(degrees) when the rotation angle was zero. After applying the formulas we find that width = 193.20 and height = -87.60
Finally, we can add those values (width and height) to the center of the square to find the coordinates of the blue point.
-Example-
// Get the center point
CGPoint squareCenter = self.squareView.center;
// Get the blue point coordinates
CGPoint bluePointCoordinates = CGPointMake(squareCenter.x + width, squareCenter.y + height);
The blue point coordinates are (963.20, 272.40)
To better understand the formulas please see the following links:
Trigonometry 1
Trigonometry 2
Also, if you want to play around with the test project I created (it's the one in the image) please feel free to download it from the following link.
UPDATE
Here is a condensed method that will calculate the offset top-right point (blue) you're looking for.
/* Params:
/ viewCenter: The center point (in superView coordinates) of your view
/ width: The total width of your view
/ height: The total height of your view
/ angleOfRotation: The rotation angle of your view. Can be either DEGREES or RADIANS
/ degrees: A boolean flag indicating whether 'angleOfRotation' is degrees
/ or radians. E.g.: If 'angleOfRotation' is expressed in degrees
/ this parameter must be 'YES'
*/
-(CGPoint)calculateTopRightCoordinatesFromViewCenter:(CGPoint)viewCenter viewWidth:(CGFloat)viewWidth viewHeight:(CGFloat)viewHeight angleOfRotation:(CGFloat)angleOfRotation degrees:(BOOL)degrees {
CGFloat adjacent = viewWidth/2.0;
CGFloat opposite = viewHeight/2.0;
CGFloat hipotenuse = sqrtf(powf(adjacent, 2.0) + pow(opposite, 2.0));
CGFloat thetaRad = acosf((powf(hipotenuse, 2.0) + powf(adjacent, 2.0) - pow(opposite, 2.0)) / (2 * hipotenuse * adjacent));
CGFloat angleRad = 0.0;
if (degrees) {
angleRad = angleOfRotation*M_PI/180.0;
} else {
angleRad = angleOfRotation;
}
CGFloat widthOffset = cosf(angleRad - thetaRad) * hipotenuse;
CGFloat heightOffset = sinf(angleRad - thetaRad) * hipotenuse;
CGPoint offsetPoint = CGPointMake(viewCenter.x + widthOffset, viewCenter.y + heightOffset);
return offsetPoint;
}
Hope this helps!
You should use:
CGPoint CGPointApplyAffineTransform (
CGPoint point,
CGAffineTransform t
);
To get a specific point, use the view's bounds and center, and then apply the view's transform to get a new point after transform. This is better than adding code specifically for rotation transform, as it can support any transform as well as chaining.
All of these answers are nuts, this is so simple...
CGPoint topLeft = [rotatedView convertPoint:CGPointMake(0, 0) toView:rotatedView.superview];
CGPoint topRight = [rotatedView convertPoint:CGPointMake(rotatedView.bounds.size.width, 0) toView:rotatedView.superview];
CGPoint bottomLeft = [rotatedView convertPoint:CGPointMake(0, rotatedView.bounds.size.height) toView:rotatedView.superview];
CGPoint bottomRight = [rotatedView convertPoint:CGPointMake(rotatedView.bounds.size.width, rotatedView.bounds.size.height) toView:rotatedView.superview];
Try this code
CGPoint localBeforeTransform = CGPointMake( view.bounds.size.width/2.0f, view.bounds.size.height/2.0f ); // lower left corner
CGPoint localAfterTransform = CGPointApplyAffineTransform(localBeforeTransform, transform);
CGPoint globalAfterTransform = CGPointMake(localAfterTransform.x + view.center.x, localAfterTransform.y + view.center.y);
Why the mess and fuss? Keep it simple? Where x was before the transform, it'll be q rads/degrees further just as every other point around the anchor is.
was going to explain it all, but this chap in this post explained it in even shorter context:
Get the current angle/rotation/radian for a UIview?
CGFloat radians = atan2f(yourView.transform.b, yourView.transform.a);
CGFloat degrees = radians * (180 / M_PI);
I wrote this class that can help us:
TransformedViewFrameCalculator.h
#import <Foundation/Foundation.h>
#interface TransformedViewFrameCalculator : NSObject
#property (nonatomic, strong) UIView *viewToProcess;
- (void)calculateTransformedCornersWithTranslation:(CGPoint)translation
scale:(CGFloat)scale
rotation:(CGFloat)rotation;
#property (nonatomic, readonly) CGPoint transformedTopLeftCorner;
#property (nonatomic, readonly) CGPoint transformedTopRightCorner;
#property (nonatomic, readonly) CGPoint transformedBottomLeftCorner;
#property (nonatomic, readonly) CGPoint transformedBottomRightCorner;
#end
TransformedViewFrameCalculator.m:
#import "TransformedViewFrameCalculator.h"
#interface TransformedViewFrameCalculator ()
#property (nonatomic, assign) CGRect viewToProcessNotTransformedFrame;
#property (nonatomic, assign) CGPoint viewToProcessNotTransformedCenter;
#end
#implementation TransformedViewFrameCalculator
- (void)setViewToProcess:(UIView *)viewToProcess {
_viewToProcess = viewToProcess;
CGAffineTransform t = _viewToProcess.transform;
_viewToProcess.transform = CGAffineTransformIdentity;
_viewToProcessNotTransformedFrame = _viewToProcess.frame;
_viewToProcessNotTransformedCenter = _viewToProcess.center;
_viewToProcess.transform = t;
}
- (void)calculateTransformedCornersWithTranslation:(CGPoint)translation
scale:(CGFloat)scale
rotation:(CGFloat)rotation {
double viewWidth = _viewToProcessNotTransformedFrame.size.width * scale;
double viewHeight = _viewToProcessNotTransformedFrame.size.height * scale;
CGPoint viewCenter = CGPointMake(_viewToProcessNotTransformedCenter.x + translation.x,
_viewToProcessNotTransformedCenter.y + translation.y);
_transformedTopLeftCorner = [self calculateCoordinatesForViewPoint:CGPointMake(0, 0)
fromViewCenter:viewCenter
viewWidth:viewWidth
viewHeight:viewHeight
angleOfRotation:rotation];
_transformedTopRightCorner = [self calculateCoordinatesForViewPoint:CGPointMake(0, viewHeight)
fromViewCenter:viewCenter
viewWidth:viewWidth
viewHeight:viewHeight
angleOfRotation:rotation];
_transformedBottomLeftCorner = [self calculateCoordinatesForViewPoint:CGPointMake(viewWidth, 0)
fromViewCenter:viewCenter
viewWidth:viewWidth
viewHeight:viewHeight
angleOfRotation:rotation];
_transformedBottomRightCorner = [self calculateCoordinatesForViewPoint:CGPointMake(viewWidth, viewHeight)
fromViewCenter:viewCenter
viewWidth:viewWidth
viewHeight:viewHeight
angleOfRotation:rotation];
}
- (CGPoint)calculateCoordinatesForViewPoint:(CGPoint)viewPoint
fromViewCenter:(CGPoint)viewCenter
viewWidth:(CGFloat)viewWidth
viewHeight:(CGFloat)viewHeight
angleOfRotation:(CGFloat)angleOfRotation {
CGPoint centeredViewPoint = CGPointMake(viewPoint.x - viewWidth/2.0, viewPoint.y - viewHeight/2.0);
CGPoint rotatedCenteredViewPoint = CGPointApplyAffineTransform(centeredViewPoint, CGAffineTransformMakeRotation(angleOfRotation));
CGPoint rotatedViewPoint = CGPointMake(rotatedCenteredViewPoint.x + viewCenter.x, rotatedCenteredViewPoint.y + viewCenter.y);
return rotatedViewPoint;
}
For example, I use it to restrict the move/scale/rotation of a sticker inside a container view in the following way:
#property (nonatomic, strong) TransformedViewFrameCalculator *transformedFrameCalculator;
...
self.transformedFrameCalculator = [TransformedViewFrameCalculator new];
self.transformedFrameCalculator.viewToProcess = someView;
...
- (BOOL)transformedView:(UIView *)view
withTranslation:(CGPoint)translation
scale:(double)scale
rotation:(double)rotation
isFullyInsideValidFrame:(CGRect)validFrame {
[self.transformedFrameCalculator calculateTransformedCornersWithTranslation:translation
scale:scale
BOOL topRightIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedTopRightCorner);
BOOL topLeftIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedTopLeftCorner);
BOOL bottomRightIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedBottomRightCorner);
BOOL bottomLeftIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedBottomLeftCorner);
return topRightIsInsideValidFrame && topLeftIsInsideValidFrame && bottomRightIsInsideValidFrame && bottomLeftIsInsideValidFrame;
}
I'm having two issues with the attached code.
First, if I set the animation duration of shape to 1 second so that the shape is always moving then touchesBegan does not fire. When I look through the C4View.m it seems that UIViewAnimationOptionAllowUserInteraction is not set. Is there a way that I could get access to the UIView to set this option? It seems that it would be difficult without rewriting C4View.
http://iphonedevsdk.com/forum/iphone-sdk-development/64569-uiview-animatewithduration-blocks-the-screen-for-touch-input.html
Second, every time the shape is hit I want it to shrink a little bit. The problem I'm having is that after I hit it the first time it stops moving. After some digging it seems that C4Shape loses its shapeness after it is rebuilt with the new frame. Here is the console information before:
[C4Log] <C4Shape: 0x7b63820; baseClass = UIControl;
frame = (263 691; 200 200);
animations = { position=<CABasicAnimation: 0x1082c490>;
animateFillColor=<CABasicAnimation: 0x8a62c00>;
animateLineDashPhase=<CABasicAnimation: 0x8a64920>;
animateStrokeColor=<CABasicAnimation: 0x8a64ef0>;
animateStrokeEnd=<CABasicAnimation: 0x8a65190>;
animateStrokeStart=<CABasicAnimation: 0x8a65430>; };
layer = <C4ShapeLayer: 0x7b63d00>>
and after:
[C4Log] <C4Shape: 0x1082d3a0; baseClass = UIControl;
frame = (204 17; 180 180);
layer = <C4ShapeLayer: 0x1082d4e0>>
Setting shape to nil first, or redoing the animations after the redefine do not seem to solve the problem.
CODE
//
// C4WorkSpace.m
// touchgame
//
// Created by Adam Tindale on 2013-09-28.
//
#import "C4WorkSpace.h"
#implementation C4WorkSpace
{
C4Shape * shape;
C4Timer * timer;
C4Label * text;
C4Font * font;
int score;
}
-(void)setup
{
score = 0;
shape = [C4Shape ellipse:CGRectMake(self.canvas.center.x, self.canvas.center.y, 200, 200)];
font = [C4Font fontWithName:#"Chalkduster" size:40];
text = [C4Label labelWithText:#"Score : 0" font:font];
[shape setAnimationDuration:0.05];
timer = [C4Timer automaticTimerWithInterval:1.0 target:self method:#"runaway" repeats:YES];
[self listenFor:#"touchesBegan" fromObject:shape andRunMethod:#"imhit"];
[self.canvas addSubview:text];
[self.canvas addSubview:shape];
}
-(void) runaway
{
[shape setCenter:CGPointMake([C4Math randomIntBetweenA:0 andB:self.canvas.width], [C4Math randomIntBetweenA:0 andB:self.canvas.height])];
C4Log(#"%#",shape);
}
-(void) imhit
{
[text setText:[NSString stringWithFormat:#"Score: %d",++score]];
[text sizeToFit];
CGRect r = shape.frame;
r.size = CGSizeMake(shape.size.width * 0.9, shape.size.height * 0.9);
shape = [C4Shape ellipse:r];
}
#end
Interactive Animations
C4Control / C4View / C4Window all have an animation option that allows for user interaction during animations. It's part of the C4AnimationOptions struct that can be found in C4Defines.h.
Make sure to call this before you start your animations.
shape.animationOptions = ALLOWSINTERACTION;
And, just like other options it can be bitmasked:
shape.animationOptions = EASEOUT | AUTOREVERSE | ALLOWSINTERACTION;
(You don't have to rework C4View, yet!)
Changing Shape Size
To change a shape's size, you want to call methods on the shape itself like so:
[shape ellipse:r];
The following...
shape = [C4Shape ellipse:r];
... won't work for 3 reasons:
By calling C4Shape you're actually creating a new object, not affecting the one that already exists
By setting shape = [...]; you're changing the pointer from the original shape to the new one that you just created
The new shape doesn't exist on screen, the shape that stops is the original one that you added as a subview. This is why your original shape stops moving, because you're now referencing a new object.
The following code is my modified version of what you have above:
#import "C4WorkSpace.h"
#implementation C4WorkSpace
{
C4Shape * shape;
C4Timer * timer;
C4Label * text;
C4Font * font;
int score;
}
-(void)setup
{
score = 0;
shape = [C4Shape ellipse:CGRectMake(self.canvas.center.x, self.canvas.center.y, 200, 200)];
font = [C4Font fontWithName:#"Chalkduster" size:40];
text = [C4Label labelWithText:#"Score : 0" font:font];
[shape setAnimationDuration:0.05];
timer = [C4Timer automaticTimerWithInterval:1.0 target:self method:#"runaway" repeats:YES];
[self listenFor:#"touchesBegan" fromObject:shape andRunMethod:#"imhit"];
[self.canvas addSubview:text];
[self.canvas addSubview:shape];
}
-(void) runaway {
shape.animationOptions = ALLOWSINTERACTION;
[shape setCenter:CGPointMake([C4Math randomIntBetweenA:0 andB:self.canvas.width], [C4Math randomIntBetweenA:0 andB:self.canvas.height])];
C4Log(#"%#",shape);
}
-(void) imhit
{
[text setText:[NSString stringWithFormat:#"Score: %d",++score]];
[text sizeToFit];
CGRect r = shape.frame;
r.size = CGSizeMake(shape.size.width * 0.9, shape.size.height * 0.9);
[shape ellipse:r];
}
#end
I have a project in which I have to make a square and circles on a button clcik.
there are textfileds before button , on textfiled we give the value such as 45, on click on uibutton the action perform and 45 square will automatically adjust with the iphone scfreen itself.
suppose the screen size is 320 * 480 , so the square automatically adjust with the screen.
and if we give the value 300 on the Textfiled the 300 squares will create and adjust automatically on the screen.
It will Show like graph paper at one stage if we give value like 1500.
I dont have any idea how to do it and how to start and where to start.
I am just thinking that it will use Quartcore Framework , but I dont have any Idea from where I start the project what I search.
I want suggestions and idea from experts.
Any Idea or suggestions from experts would be highly welcome.
// Step 1 : Add QuartzCore.framework in your project
// Step 2 : Create following two files .h and .m
// Step 3 : How to Use
// Import your custom file
#import "myDrawingView.h"
// Create object and add to your viewcontroller
myDrawingView *obj = [[myDrawingView alloc] initWithFrame:self.view.frame];
[obj drawSquaresWithNumber:17 andSize:self.view.frame.size];
[self.view addSubview:obj];
//------------------------------------------------------
// filename : myDrawingView.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface myDrawingView : UIView
{
int nSquares;
CGSize mazeSize;
}
- (void)drawSquaresWithNumber:(int)numberOfSquares andSize:(CGSize)screenSize;
#end
//------------------------------------------------------
// filename : myDrawingView.m
#import "myDrawingView.h"
#implementation myDrawingView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
// Calculate height and width for each sqaure.
float area = mazeSize.height*mazeSize.width;
float squareSize = (area/nSquares)/100;
NSLog(#"row : %f %f",mazeSize.width/squareSize,mazeSize.height/squareSize);
int row, col;
row = ceil(mazeSize.width/squareSize);
col = ceil(mazeSize.height/squareSize);
float height = mazeSize.height/row;
float width = mazeSize.width/col;
NSLog(#"%d %d",row,col);
NSLog(#"h %f w %f",height,width);
NSLog(#"square size : %f",squareSize);
// Create Current Context To Draw
CGContextRef context = UIGraphicsGetCurrentContext();
// Draw Line
CGContextSetLineWidth(context, 0.5f);
CGContextSetFillColorWithColor(context, [myDrawingView randomColor].CGColor);
CGContextSetStrokeColorWithColor(context, [myDrawingView randomColor].CGColor);
int x ,y, cnt;
x = y = 0;
cnt = 1;
// A loop for number of squares
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
if(cnt<=nSquares)
{
CGRect rect = CGRectMake(x, y, width, height);
// Draws Squares
UIBezierPath *path = [UIBezierPath bezierPathWithRect:rect];
// To draw Oval uncomment
// UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:rect];
[path fill];
[path stroke];
}
x += width;
cnt++;
}
x = 0;
y += height;
}
}
+ (UIColor *) randomColor {
CGFloat red = arc4random()%256;
CGFloat blue = arc4random()%256;
CGFloat green = arc4random()%256;
return [UIColor colorWithRed:abs(red)/255.0f green:abs(green)/255.0f blue:abs(blue)/255.0f alpha:1.0];
}
- (void)drawSquaresWithNumber:(int)numberOfSquares andSize:(CGSize)screenSize
{
nSquares = numberOfSquares;
mazeSize = screenSize;
[self setNeedsDisplay];
}
#end
Create a button, a label and 2 textfield's (one for height, one for width). Set a 1pixel border on the label and set the width and height of the label to the screen size. Create an IBAction for the button and assign the width and height of the label based on the content inside the textfield's. This will create the square. To create the circle you can either use QuartzCore and set the corner radius to half of the height/width or you can draw this programatically. This is the quickest way to achieve what you are asking without getting too far into drawing on screen with GL and would be a good start for understanding how actions and inputs work.
i'm implementing zooming and rotation using UIImageview in my project,
i'm facing problem in zoom in and zoom out after rotating the image,
Here is my code follows:
in .h file
#interface ViewController : UIViewController{
float degrees;
float height;
float width;
float moveLeft;
float moveRight;
}
#property(nonatomic,retain)UIImageView *imageView;
-(IBAction)rotationLeft:(id)sender;
-(IBAction)rotationRight:(id)sender;
-(IBAction)zoomIn:(id)sender;
-(IBAction)zoomOut:(id)sender;
-(IBAction)moveLeft:(id)sender;
-(IBAction)moveRight:(id)sender;
in .m file
- (void)viewDidLoad
{
[super viewDidLoad];
height=50;
width=50;
degrees=20;
moveLeft=20;
moveRight=20;
imageView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"1.png"]];
imageView.frame=CGRectMake(100, 100,width, height);
[self.view addSubview:imageView];
// Do any additional setup after loading the view, typically from a nib.
}
-(IBAction)rotationLeft:(id)sender{
//the value in degrees
imageView.transform = CGAffineTransformMakeRotation(degrees*M_PI/180);
degrees=degrees+25;
}
-(IBAction)rotationRight:(id)sender{
//the value in degrees
degrees=degrees-25;
imageView.transform = CGAffineTransformMakeRotation(degrees*M_PI/180);
}
-(IBAction)zoomIn:(id)sender{
height=height-15;
width=width-15;
imageView.frame=CGRectMake(100, 100,width, height);
}
-(IBAction)zoomOut:(id)sender{
height=height+15;
width=width+15;
imageView.frame=CGRectMake(100, 100,width, height);
}
Please find the attached image for your reference.
you should use CGAffineTransformMakeScale for zooming purposes, instead of forcing the frame.
define somewhere a global foal x = 1; then:
-(IBAction)zoomIn:(id)sender{
x += 0.3;
imageView.transform = CGAffineTransformMakeScale(x, x);
}
-(IBAction)zoomOut:(id)sender{
x -= 0.3;
imageView.transform = CGAffineTransformMakeScale(x, x);
}
I would recommend scaling the image using a very similar method to the rotation code that you have:
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy);
Just send it more than 1.0 to scale up and less than 1.0 to scale down;
Below code worked for me perfect!!!
-(IBAction)rotationLeft:(id)sender{
//the value in degrees
degrees=degrees+25;
CGAffineTransform t;
t=CGAffineTransformMakeScale(x, x);
// imageView.transform = CGAffineTransformMakeRotation(degrees*M_PI/180,x,x);
imageView.transform=CGAffineTransformRotate(t, degrees*M_PI/180);
}
-(IBAction)rotationRight:(id)sender{
degrees=degrees-25;
CGAffineTransform t;
t=CGAffineTransformMakeScale(x, x);
imageView.transform=CGAffineTransformRotate(t, degrees*M_PI/180);
}
-(IBAction)zoomIn:(id)sender{
x += 0.3;
CGAffineTransform t;
t=CGAffineTransformMakeRotation(degrees*M_PI/180);
imageView.transform=CGAffineTransformScale(t, x, x);
}
-(IBAction)zoomOut:(id)sender{
x -= 0.3;
CGAffineTransform t;
t=CGAffineTransformMakeRotation(degrees*M_PI/180);
imageView.transform=CGAffineTransformScale(t, x, x);
}