Reputation: 1093
[edit]
ORIGINAL QUESTION STARTS BELOW. HERE IS MORE INFO
I've been working on this issue all day and can't find a resolution. I have subclassed a UIView and cut down the drawing code to the following.
-(void)drawRect:(CGRect)rect
{
//// rechargeLevel Drawing
CGRect rechargeLevelRect = CGRectMake(17.5, 17.75, 64, 64);
UIBezierPath* rechargeLevelPath = [UIBezierPath bezierPath];
[rechargeLevelPath addArcWithCenter: CGPointMake(CGRectGetMidX(rechargeLevelRect), CGRectGetMidY(rechargeLevelRect)) radius: rechargeLevelRect.size.width / 2 startAngle: 90 * M_PI/180 endAngle: endAngle * M_PI/180 clockwise: YES];
[[UIColor redColor] setStroke];
rechargeLevelPath.lineWidth = 4.5;
[rechargeLevelPath stroke];
endAngle++;
if (endAngle > 359) {
endAngle = 1;
}
}
I've tried all of the following things.
drawRect: With a timer that calls setNeedsDisplay (Also tried setNeedsDisplayInRect:
CAShapeLayer with a timer that calls a method that draws the shape
CAShapeLayer inside a block that is called after a delay and then recalls itself. Because I was thinking the timer was screwing things up.
Created a second subclass of UIView with all the same code but with different labels. Initializing one of each still doesn't work.
I've tried combinations of the above methods between the two subclasses and still nothing.
Either the timer stops when you start another or its all using the same context. I have no idea.
I have created a GitHub repository with the test project I've made. It has a viewController with six buttons that initialize each of the above methods from the two subclasses and adds them to the view.
the GitHub repo is: https://github.com/MoseCode/drawTest
[end edit]
ORIGINAL QUESTION FOLLOWS:
Trying to do custom DrawRect drawing with a timer to multiple objects at the same time.
I have a custom UIController (WP_BonusController) set to receive touch events. After the controller has been touched 5 times it disables the events until a specified time has passed.
To illustrate the recharging time, I am drawing a circle path from DrawRect. I am using UIGraphicsGetCurrentContext and then stroking the new path.
My problem is when I instantiate a bunch of these WP_BonusController objects they all are sharing the same context from UIGraphicsGetCurrentContext. I checked the ram allocations for the objects and they are all different. But when I put a breakpoint in the drawRect: and check the CGContextRef from UIGraphicsGetCurrentContext they all have the same ram allocation.
When I tap bonusController1 five times the timer starts and starts drawing the circle around the icon. it works fine.
Then I press bonusController2 five times and it starts it's timer but when it draws the context in it's drawRect I get the same context from the other bonusController1. So the line being drawn is already half drawn on.
This is the same for any number of these controllers.
Is there a way I can create my own clean context that doesn't use the UIGraphicsGetCurrentContext. I've been searching all over and can't find a solution. Maybe I am not understanding the usage of the context correctly. I need to be able to draw to these controllers individually at any time and many times concurrently.
Here is my drawRect: that gets called by a timer:
-(void)drawRect:(CGRect)rect
{
_currentAngle = _currentAngle + 1;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.frame.size.width, self.frame.size.height), NO, 0);
// General Declarations
CGContextRef context = UIGraphicsGetCurrentContext();
// Resize to Target Frame
CGContextSaveGState(context);
CGRect resizedFrame = WP_CustomIconsResizingBehaviorApply(WP_CustomIconsResizingBehaviorAspectFill, CGRectMake(0, 0, 100, 100), [self getImageRect]);
CGContextTranslateCTM(context, resizedFrame.origin.x, resizedFrame.origin.y);
CGContextScaleCTM(context, resizedFrame.size.width / 100, resizedFrame.size.height / 100);
//// rechargeLevel Drawing
CGRect rechargeLevelRect = CGRectMake(17.5, 17.75, 64, 64);
UIBezierPath* rechargeLevelPath = [UIBezierPath bezierPath];
[rechargeLevelPath addArcWithCenter: CGPointMake(CGRectGetMidX(rechargeLevelRect), CGRectGetMidY(rechargeLevelRect)) radius: rechargeLevelRect.size.width / 2 startAngle: 90 * M_PI/180 endAngle: _currentAngle * M_PI/180 clockwise: YES];
[WP_CustomIcons.thirdColor setStroke];
rechargeLevelPath.lineWidth = 4.5;
[rechargeLevelPath stroke];
CGContextRestoreGState(context);
refillMeter = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.refillImageView setImage:refillMeter];
}
Upvotes: 0
Views: 61
Reputation: 1093
figured it out. Last one to try. Maybe should have been the first but I was for some reason just thinking of timers.
CALayerAnimation
@implementation ThirdTimerView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//
}
return self;
}
-(UIBezierPath *)samplePath
{
CGRect rechargeLevelRect = CGRectMake(17.5, 17.75, 64, 64);
UIBezierPath* rechargeLevelPath = [UIBezierPath bezierPath];
[rechargeLevelPath addArcWithCenter: CGPointMake(CGRectGetMidX(rechargeLevelRect), CGRectGetMidY(rechargeLevelRect)) radius: rechargeLevelRect.size.width / 2 startAngle: 90 * M_PI/180 endAngle: 450 * M_PI/180 clockwise: YES];
return rechargeLevelPath;
}
- (void)startAnimation
{
if (self.pathLayer == nil)
{
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [[self samplePath] CGPath];
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.fillColor = nil;
shapeLayer.lineWidth = 4.5f;
shapeLayer.lineJoin = kCALineJoinBevel;
[self.layer addSublayer:shapeLayer];
self.pathLayer = shapeLayer;
}
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeTimer"];
pathAnimation.duration = 3.0;
pathAnimation.fromValue = @(0.0f);
pathAnimation.toValue = @(1.0f);
[CATransaction setCompletionBlock:^{
[self removeFromSuperview];
}];
[self.pathLayer addAnimation:pathAnimation forKey:@"strokeTimer"];
}
@end
Upvotes: 0