How to rotate a line to 90 degree using animation in Xcode? - xcode

I have a line drawn over the circle using UIBezierPath and CAShapeLayer which lies vertically. I want to rotate the line to 90 degree along with animation so that after animation the line lies horizontally.I have tried many animation solutions but the line does not rotates along the circle with same center point and it goes out of the circle. I need to rotate the line with animation without changing the center point.
UIBezierPath *CirclePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(_width*4, _height*4) radius: (_width*3.5)
startAngle:0 endAngle: (2*3.14) clockwise:YES];
CAShapeLayer *Circlelayer = [CAShapeLayer layer];
Circlelayer.path = [CirclePath CGPath];
Circlelayer.strokeColor = [[UIColor orangeColor]CGColor];
Circlelayer.lineWidth = _width*0.6;
Circlelayer.fillColor = [[UIColor clearColor] CGColor];
[self.layer addSublayer:Circlelayer];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(_width*4, _height*0.2)];
[path addLineToPoint:CGPointMake(_width*4, _height*7.8)];
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.path = [path CGPath];
pathLayer.strokeColor = [[UIColor whiteColor]CGColor];
pathLayer.lineWidth = _width*0.8;
pathLayer.fillColor = [[UIColor whiteColor]CGColor];
[self.layer addSublayer:pathLayer];
Thanks in advance.

You can add pathLayer as sublayer to circleLayer, so whenever transformation applied to the circleLayer will also aplied to pathLayer.

Related

UIImageView frame origin after applying CAKeyframeAnimation

I have an UIImageView that I am moving around a circle with CGAffineTransformRotate. Works great! But when the user press a stop bottom I would like to the the actual x- / y- position of the UIImageView. So far I am always getting the original x- / y- values from when the UIImageView was created.
Is there a way to get the actual position, when the user stopped the rotation?
I have found the solution and share it in case someone is running a similar case:
From UIBezierPath I use the bounds information and this give me the position where the UIImageView stopped. Here the code:
UIBezierPath *path = [[UIBezierPath alloc] init];
[path addArcWithCenter:CGPointMake(iMiddleX, iMiddleY) radius:flR startAngle:degreesToRadians(flDegrees-0.01) endAngle:degreesToRadians(flDegrees) clockwise:YES];
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
pathAnimation.repeatCount = 1;
pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
pathAnimation.duration = 1.0;
pathAnimation.path = path.CGPath;
NSInteger iX = path.bounds.origin.x;
NSInteger iY = path.bounds.origin.y;

rotate a sublayer in xcode

It's been a while, as I was hospitalized for 3 months after a motorcycle accident.
So I just got to renew my apple programming subscription :-)
I have another question that has been on my mind for quite some time.
In my iPad application I draw a triangle in the center of an iPad like this:
- (void)initTriangle
{
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
// draw triangle (TRIANGLE)
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path,NULL, 0.5*screenWidth, 0.5*screenHeight-25);
CGPathAddLineToPoint(path, NULL, 0.5*screenWidth-25, 0.5*screenHeight+25);
CGPathAddLineToPoint(path, NULL, 0.5*screenWidth+25, 0.5*screenHeight+25);
CGPathAddLineToPoint(path, NULL, 0.5*screenWidth, 0.5*screenHeight-25);
CAShapeLayer *triangle = [CAShapeLayer layer];
[triangle setPath:path];
[triangle setFillColor:[[UIColor blackColor] CGColor]];
[[[self view] layer] addSublayer:triangle];
CGPathRelease(path);
}
And I call this from my viewDidLoad like this:
[self initTriangle];
Now I'm trying to rotate this triangle with the rotation of my iPad around Z-Axis while laying flat on the table. I have a function that gives me the yaw readings in float and I'm calling my
-(void)updateTriangleWithYaw:(float)yaw
method, but I don't know what to exactly put in there to make it rotate.
here is what my method looks like so far:
-(void)updateTriangleWithYaw:(float)yaw
{
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
NSLog(#"YAW: %f", yaw);
Z += 2 * yaw;
Z *= 0.8;
CGFloat newR = R + 10 * yaw;
self.triangle.frame = CGRectMake(0.5*screenWidth, 0.5*screenHeight, newR, newR);
}
Any help will be greatly appreciated!
Thanks and be safe guys!!
You should set the layer's affineTransform. You can apply a rotation transform like:
[self.triangle setAffineTransform:CGAffineTransformMakeRotation(yaw)];
This method, setAffineTransform is a convenience to set the transform property of the layer, which is a more general type of transform CATransform3D. You can also set the transform of the layer directly, and if you want to do that you can make a rotation about the z-axis like:
self.triangle.transform = CATransform3DMakeRotation(yaw, 0, 0, 1);
In this case the first argument is the angle (in radians) and the last three arguments specify the axis of rotation.
Note that you should not assign or depend on the value of the frame property of a layer whose transform is not the identity (CGAffineTransformIdentity). When you use the transform property you should set the size and position of your layer by assigning the layer's center and bounds properties, and similarly you should read the center and bounds when you want to find out information about the layer's position and size.

How do I draw a top-right rounded corner on a NSButton?

There are several ways to four draw rounded corners in Cocoa, either using CALayer or NSBezierPath. But how can I draw a single rounded corner on a NSButton?
The current structure of the button is:
NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 50, 20)];
[button setTitle:#"My button"];
[button.cell setBackgroundColor:[NSColor grayColor]];
What I want to do is have a rounded top-right corner with a radius of 10. How do I do that?
SOLUTION:
Override drawRect:
CGFloat cornerRadius = 10;
NSBezierPath *path = [NSBezierPath bezierPath];
// Start drawing from upper left corner
[path moveToPoint:NSMakePoint(NSMinX(self.bounds), NSMinY(self.bounds))];
// Draw top border and a top-right rounded corner
NSPoint topRightCorner = NSMakePoint(NSMaxX(self.bounds), NSMinY(self.bounds));
[path lineToPoint:NSMakePoint(NSMaxX(self.bounds) - cornerRadius, NSMinY(self.bounds))];
[path curveToPoint:NSMakePoint(NSMaxX(self.bounds), NSMinY(self.bounds) + cornerRadius)
controlPoint1:topRightCorner
controlPoint2:topRightCorner];
// Draw right border, bottom border and left border
[path lineToPoint:NSMakePoint(NSMaxX(self.bounds), NSMaxY(self.bounds))];
[path lineToPoint:NSMakePoint(NSMinX(self.bounds), NSMaxY(self.bounds))];
[path lineToPoint:NSMakePoint(NSMinX(self.bounds), NSMinY(self.bounds))];
// Fill path
[[NSColor whiteColor] setFill];
[path fill];
You need to use NSBezierPath and draw a custom button as per your requirement.
You need to work something like this :
NSBezierPath *path = [NSBezierPath bezierPath];
[path setLineWidth:1];
[path moveToPoint:NSMakePoint(0, 0)];
[path curveToPoint:NSMakePoint(width * 0.1, height)
controlPoint1:NSMakePoint(width * 0.05, height)
controlPoint2:NSMakePoint(width * 0.03, height * 0.05)];
And so on... Untill you make a closed button area and you get exact shape.
Based on Christoffer Christoffer's approach, I've created a more general solution where you can choose which corner you want to round. It's in Swift 3 and also works on both macOS & iOS/tvOS.
You can find the Swift Playground here: https://github.com/janheiermann/BezierPath-Corners

Concave NSBezierPath

I have the following drawing code:
[[NSColor redColor] set];
NSRect fillRect = NSMakeRect(bounds.size.width - 20.0f, 0.0f, 20.0f, 20.0f);
NSBezierPath *bezier1 = [NSBezierPath bezierPathWithRoundedRect:fillRect xRadius:10.0f yRadius:10.0f];
[bezier1 fill];
NSRect fill2 = fillRect;
fill2.origin.x += 5;
fill2.origin.y += 5;
fill2.size.width -= 10.0f;
fill2.size.height -= 10.0f;
NSBezierPath *bezier2 = [NSBezierPath bezierPathWithRoundedRect:fill2 xRadius:5.0f yRadius:5.0f];
[[NSColor greenColor] set];
[bezier2 fill];
Which result in this:
How do I reach that the inner green circle is transparent? Replacing the green NSColor with a transparent color doesn't work, logical ;-)
Is there a way to intersect instances of NSBezierPath or solve this with another approach?
I think what you're looking for is a bezier path for a ring, you can do that by creating a single NSBezierPath and setting the winding rule:
[[NSColor redColor] set];
NSRect fillRect = NSMakeRect(bounds.size.width - 20.0f, 0.0f, 20.0f, 20.0f);
NSBezierPath *bezier1 = [NSBezierPath new];
[bezier1 setWindingRule:NSEvenOddWindingRule]; // set the winding rule for filling
[bezier1 appendBezierPathWithRoundedRect:fillRect xRadius:10.0f yRadius:10.0f];
NSRect innerRect = NSInsetRect(fillRect, 5, 5); // the bounding rect for the hole
[bezier1 appendBezierPathWithRoundedRect:innerRect xRadius:5.0f yRadius:5.0f];
[bezier1 fill];
The NSEvenOddWindingRule rule determines whether to fill a particular point by considering a line from that point to outside the overall path bounds; if that line crosses an even number of paths it is not filled, otherwise it is. So any point in the inner circle will not be filled, while points between the two will be - result a ring.

cocos2d screen size problem in landscape mode

I have such a problem in my cocos2d application in landscape mode:
When I'm adding a new object inherited from CCNode and add it to layer and after that layer to screen. The maximum position must be 480 on X and 320 on Y in landscape mode. But my object is in position 480 on X when it coordinates are on (220, 0). Anybody know how to solve this problem?? Thanx!
- (void) applicationDidFinishLaunching:(UIApplication*)application
{
CCScene *scene = [CCScene node];
CCLayer *layer = [CCLayer node];
//layer.anchorPoint = ccp(1, 1);
//layer.contentSize = CGSizeMake(480, 320);
CCSprite *sp = [CCSprite spriteWithFile:#"fon.png"];
[layer addChild: sp];
[scene addChild: layer];
[[CCDirector sharedDirector] runWithScene: scene];
}
I think you are misunderstanding the co-ordinates.
x and y are the same on the phone, regardless of orientation.
When the phone is on its side, x = y and y = x.
Try this
player1 = [[Player alloc] initWithPosition: CGPointMake(20, 200) )];

Resources