I am trying to create a view animation similar to facebook's expanding X when removing a message in the iPhone version. The problem I am facing right now is, I am animating the parent view's bounds using core animation and the resulting subviews animations are animating with it. Ultimately what I want is the parent view to animate and the subview to remain unanimated, in the center of it's parent's view. Below is the code I am using.
#interface FCXView : UIView
#end
#implementation FCXView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.layer.opacity = 1.0f;
self.alpha = 1.0f;
self.autoresizingMask = UIViewAutoresizingNone;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat lineWidth2 = 1.0f;
CGContextSetLineWidth(context, lineWidth2);
CGFloat red[4] = {1.0f, 0.0f, 0.0f, 0.9f};
CGContextSetStrokeColor(context, red);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 17.0f, 15.0f);
CGContextAddLineToPoint(context, 28.0f, 30.0f);
CGContextStrokePath(context);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 28.0f, 15.0f);
CGContextAddLineToPoint(context, 17.0f, 30.0f);
CGContextStrokePath(context);
CGContextFillPath(context);
}
#end
#interface FCRoundView ()
#end
#implementation FCRoundView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
self.layer.opacity = 1.0f;
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = NO;
self.autoresizesSubviews = NO;
[self setupXView];
}
return self;
}
- (void)setupXView
{
// Load X
FCXView *xView = [[FCXView alloc] initWithFrame:CGRectMake(0, 0, 45, 45)];
[self addSubview:xView];
}
- (void)drawRect:(CGRect)rect
{
CGFloat lineWidth = 5;
CGRect borderRect = CGRectInset(rect, lineWidth * 0.5, lineWidth * 0.5);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetRGBFillColor(context, 175.0/255.0, 175.0/255.0, 175.0/255.0, 0.6);
CGContextSetLineWidth(context, 5.0);
CGContextFillEllipseInRect (context, borderRect);
CGContextStrokeEllipseInRect(context, borderRect);
}
#pragma mark - Handle touch
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.bounds.size.height == 45) {
SKBounceAnimation *bounceAnimation = [SKBounceAnimation animationWithKeyPath:#"bounds"];
bounceAnimation.fromValue = [NSValue valueWithCGRect:self.frame];
bounceAnimation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 75, 75)];
bounceAnimation.duration = 0.5f;
bounceAnimation.numberOfBounces = 4;
bounceAnimation.delegate = self;
bounceAnimation.removedOnCompletion = NO;
bounceAnimation.fillMode = kCAFillModeForwards;
bounceAnimation.shouldOvershoot = YES;
[self.layer addAnimation:bounceAnimation forKey:#"someKey"];
}
else {
SKBounceAnimation *bounceAnimation = [SKBounceAnimation animationWithKeyPath:#"bounds"];
bounceAnimation.fromValue = [NSValue valueWithCGRect:self.frame];
bounceAnimation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 45, 45)];
bounceAnimation.duration = 0.5f;
bounceAnimation.numberOfBounces = 4;
bounceAnimation.delegate = self;
bounceAnimation.removedOnCompletion = NO;
bounceAnimation.fillMode = kCAFillModeForwards;
[self.layer addAnimation:bounceAnimation forKey:#"someKey1"];
}
}
- (void)animationDidStop:(SKBounceAnimation *)animation finished:(BOOL)flag
{
[self.layer setValue:animation.toValue forKeyPath:animation.keyPath];
[self.layer removeAnimationForKey:#"someKey"];
[self.layer removeAnimationForKey:#"someKey1"];
}
Related
I drew the line that turn like clock.
This is the line's moving of my ideal
but my code moves like this
How can I make a line like the second picture's line?
Here is my code
LineLayer.m
- (void)drawInContext:(CGContextRef)ctx
{
CGMutablePathRef path = CGPathCreateMutable();
CGPoint points[] = {
CGPointMake(160, 220),
CGPointMake(160, 120),
};
int numPoints = sizeof(points)/sizeof(points[0]);
CGPathAddLines(path, NULL, points, numPoints);
CGContextAddPath(ctx, path);
CGPathRelease(path);
UIColor *lineColor = [UIColor colorWithWhite:1.0 alpha:1.0];
CGContextSetStrokeColorWithColor(ctx, lineColor.CGColor);
CGContextSetLineWidth(ctx, 5.0);
CGContextDrawPath(ctx, kCGPathStroke);
}
ViewController.h
- (void)setup
{
LineLayer *linelayer = [LineLayer layer];
linelayer.frame = CGRectInset(self.view.bounds,0.0,0.0);
linelayer.anchorPoint = CGPointMake(0.5, 0.5);
[self.view.layer addSublayer:linelayer];
[linelayer setNeedsDisplay];
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
animation.toValue = [NSNumber numberWithFloat:M_PI / 2.0];
animation.duration = 0.5;
animation.repeatCount = MAXFLOAT;
animation.cumulative = YES;
[linelayer addAnimation:animation forKey:#"ImageViewRotation"];
}
you need a clock seconds needle or something like that??
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
NSTimer *timer1;//global declaration
CALayer *layerLine;//global declaration
in viewDidLoad()
layerLine = [CALayer layer];
[layerLine setFrame:CGRectMake(0, 0,2, 90)];
[layerLine setBackgroundColor:[UIColor yellowColor].CGColor];
[self.view.layer addSublayer:layerLine];
CGPoint centerPoint = CGPointMake([[UIScreen mainScreen] bounds].size.width/2, ([[UIScreen mainScreen] bounds].size.height/2)-(layerLine.frame.size.height/4));
layerLine.anchorPoint = CGPointMake(0, 0);
layerLine.position = centerPoint;
layerLine.transform = CATransform3DMakeRotation(M_PI_2*2, 0.0, 0.0, 1.0);
if (!timer)
{
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(onTickTick) userInfo:nil repeats:YES];
}
timer invoking method
-(void)onTickTick
{
static int i = 180;
if (i==540)//if u change the value for i, it may affect this condition
{
i=180;
}
i=i+6;//u can replace 6 with 30 or any other value as u require
layerLine.transform = CATransform3DMakeRotation(DEGREES_TO_RADIANS(i), 0.0, 0.0, 1);
}
I have a UIView that contains some subviews - drawn using UIBezierPath. Every subview contains a scrollview having image as mask. When I try to render image of whole view (overall), instead of making image from path, it draws image of individual rect of subviews. Let me make it clear by figure:
Original View:
What I am getting after rendering Image:
I don't know what am I missing. Please guide me. Thanks.
Code:
IrregularSquare
#interface IrregularSquare : UIView
{
UIScrollView *imageResizer;
CAShapeLayer *maskLayer;
}
#end
#implementation IrregularSquare
- (id)initWithFrame:(CGRect)frame index:(NSInteger) index
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
self.layer.backgroundColor = [UIColor clearColor].CGColor;
}
return self;
}
-(void) drawRect:(CGRect)rect
{
UIBezierPath *aPath = [UIBezierPath bezierPath];
[aPath moveToPoint:CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect))];
[aPath addLineToPoint:CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect))];
[aPath addLineToPoint:CGPointMake(CGRectGetMaxX(rect) - 20, CGRectGetMidY(rect) - 10)];
[aPath addLineToPoint:CGPointMake(CGRectGetMaxX(rect) - 5, CGRectGetMaxY(rect) - 10)];
[aPath addLineToPoint:CGPointMake(CGRectGetMidX(rect) + 10, CGRectGetMaxY(rect))];
[aPath addLineToPoint:CGPointMake(CGRectGetMidX(rect) - 20, CGRectGetMaxY(rect) - 20)];
[aPath addLineToPoint:CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect) - 20)];
[aPath closePath];
aPath.lineWidth = 2;
[[UIColor whiteColor] setStroke];
[aPath stroke];
[self initializeImageWithPath]; //this method adds scrollview to main view and assigns an image to scrollview with mask
}
-(void) initializeImageWithPath
{
CGRect aFrame = somevalue;
self.backImage = [[UIImageView alloc] initWithFrame:aFrame];
self.backImage.contentMode = UIViewContentModeScaleAspectFill;
self.backImage.clipsToBounds = YES;
imageResizer = [[UIScrollView alloc] initWithFrame:self.bounds];
imageResizer.showsHorizontalScrollIndicator = imageResizer.showsVerticalScrollIndicator = NO;
imageResizer.scrollEnabled = YES;
imageResizer.backgroundColor = [UIColor clearColor];
imageResizer.zoomScale = 1.0;
imageResizer.delegate = self;
imageResizer.clipsToBounds = YES;
[imageResizer addSubview:self.backImage];
[self addSubview: imageResizer];
maskLayer = [CAShapeLayer layer];
maskLayer.path = [aPath CGPath];
self.layer.mask = maskLayer;
}
IrregularShapesContainer.m
#implementation IrregularShapesContainer
-(void) drawSubviews
{
for(UIView *aView in self.subviews)
[aView removeFromSuperview];
IrregularSquare *sq1 = [[IrregularSquare alloc] initWithFrame:CGRectMake(HORIPADDING, VERTICALPADDING, (self.frame.size.width - (HORIPADDING * 2) - (SPACING * 2)) * .5, (self.frame.size.height - (VERTICALPADDING) - SPACING) * .5) index:1];
[self addSubview:sq1];
[sq1.layer display];
[self randomlyPlaceImage:sq1];
sq1.irrViewDelegate = self;
//many similar instances are added in following code
}
#end
I hope my Question is clear.. Any help is appreciated.
Is there any way we can make only the selected area of a superview transparent? I have a UIView with black (alpha 0.5) background color. I am putting some hollow circles on the UIView and want the underneath UIView to be transparent so that I could see through it. Any idea
- (id)initWithFrame:(CGRect)iFrame andHollowFrames:(NSArray *)iHollowFrames withRadius:(NSNumber *)iRadius {
if ((self = [super initWithFrame:iFrame]) != nil) {
self.hollowFrames = [[NSSet setWithArray:iHollowFrames] allObjects];
self.hollowCircleRadius = iRadius;
[self addShadowView];
}
return self;
}
- (void)addShadowView {
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height) cornerRadius:0];
for (NSValue *point in self.hollowFrames) {
UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(point.CGPointValue.x - self.hollowCircleRadius.floatValue, point.CGPointValue.y - self.hollowCircleRadius.floatValue, 2.0 * self.hollowCircleRadius.floatValue, 2.0 * self.hollowCircleRadius.floatValue) cornerRadius:self.hollowCircleRadius.floatValue];
[path appendPath:circlePath];
}
[path setUsesEvenOddFillRule:YES];
CAShapeLayer *fillLayer = [CAShapeLayer layer];
fillLayer.path = path.CGPath;
fillLayer.fillRule = kCAFillRuleEvenOdd;
fillLayer.fillColor = [UIColor blackColor].CGColor;
fillLayer.opacity = 0.5;
[self.layer addSublayer:fillLayer];
}
Here is a UIView subclass solution. In order for this to work you must leave the superviews backgroundColor property as nil witch is the default value. If this UIView-subclass is in the storyboard then make sure you set the background color to "Clear color" in the attributes inspector.
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
UIColor *blackBackgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
CGContextSetFillColorWithColor(ctx, blackBackgroundColor.CGColor);
CGContextFillRect(ctx, rect);
CGRect transparentPart = CGRectMake(10, 10, 120, 80);
CGContextClearRect(ctx, transparentPart);
}
I'm working through a challenge in Big Nerd Ranch's iOS Programming guide in a chapter on UIView subclassing.
I have some code below that draws concentric circles in random colors. And, upon a shake, it should change them all to red. It doesn't because after red is set, drawRect is called again and the random color loop is redone.
Would the correct way to implement this be to move the random color loop somewhere out of drawRect? Do I set a semaphore (messy) to make sure the loop only runs once?
Thanks for your advice.
- (void)setCircleColor:(UIColor *)clr
{
circleColor = clr;
[self setNeedsDisplay];
}
- (BOOL) canBecomeFirstResponder
{
return YES;
}
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake) {
[self setCircleColor:[UIColor redColor]];
}
}
-(void)drawRect:(CGRect)dirtyRect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect bounds = [self bounds];
// Figure out the center of the bounds rectangle
CGPoint center;
center.x = bounds.origin.x + bounds.size.width / 2.0;
center.y = bounds.origin.y + bounds.size.height / 2.0;
float maxRadius = hypot(bounds.size.width, bounds.size.height) / 2.0;
CGContextSetLineWidth(ctx, 10);
// Set up an array of colors
UIColor *red = [UIColor redColor];
UIColor *green = [UIColor greenColor];
UIColor *yellow = [UIColor yellowColor];
NSArray *colors = [[NSArray alloc]initWithObjects:red, green, yellow, nil];
// Draw concentric circles from the outside in
for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {
CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2, YES);
// Random index for colors array
NSUInteger randomIndex = arc4random() % [colors count];
[self setCircleColor:[colors objectAtIndex:randomIndex]];
[[self circleColor] setStroke];
// Perform drawing; remove path
CGContextStrokePath(ctx);
}
NSString *text = #"You are getting sleepy.";
UIFont *font = [UIFont boldSystemFontOfSize:28];
CGRect textRect;
textRect.size = [text sizeWithFont:font];
// Let's put that string in the center of the view
textRect.origin.x = center.x - textRect.size.width / 2.0;
textRect.origin.y = center.y - textRect.size.height / 2.0;
[[UIColor blackColor] setFill];
// Draw a shadow
CGSize offset = CGSizeMake(4, 3);
CGColorRef color = [[UIColor darkGrayColor] CGColor];
CGContextSetShadowWithColor(ctx, offset, 2.0, color);
[text drawInRect:textRect withFont:font];
}
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setBackgroundColor:[UIColor clearColor]];
[self setCircleColor:[UIColor lightGrayColor]];
}
return self;
}
#end
Make a BOOL isSHake and cancel the random colors after you shake the device, the circles will remain red and you can reset that upon another action.
I am drawing some custom lines using custom MKAnnotationView on MapView control. The drawing is between two defined points. The problem I am facing is that, when I zoom in or zoom out in an iPhone, the lines seems to zoom in and out too. This creates a weird effect as lines appear to be over different buildings and places once the user zoom in or out. How can I solve this problem?
Here is the code for custom AnnotationView:
#implementation JogAnnotationView
#synthesize points;
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier pts:(NSMutableArray *)p
{
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self != nil)
{
CGRect cgRect =[[UIScreen mainScreen] bounds];
CGSize cgSize = cgRect.size;
CGRect frame = self.frame;
frame.size = CGSizeMake(cgSize.width/2, cgSize.height/2);
self.frame = frame;
self.backgroundColor = [UIColor clearColor];
self.centerOffset = CGPointMake(-5, -5);
self.points = p;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
NSLog(#"%d",self.points.count);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextBeginPath (context);
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
for (int i = 0; i < ([self.points count] - 1); i++)
{
JogPoint *startPoint = (JogPoint *) [self.points objectAtIndex:i];
JogPoint *endPoint = (JogPoint *) [self.points objectAtIndex:(i+1)];
CGContextMoveToPoint(context, startPoint.x ,startPoint.y);
CGContextAddLineToPoint(context,endPoint.x,endPoint.y);
}
}