UIView drawRect: when you draw a line, the rect area will be clear so the previous drawing is gone
It is quite hard to tell so I upload an image to show my problem: http://i42.tinypic.com/2eezamo.jpg
Basically in drawRect, I will draw the line from touchesMoved as finger touches and I will call "needsDisplayInRect" for redraw. But I found that the first line is done, the second line will clear the rect part, so some previouse drawing is gone.
Here is my implementation:
enter code here
-(void) drawRect:(CGRect)rect{
//[super drawRect: rect];
CGContextRef context = UIGraphicsGetCurrentContext();
[self drawSquiggle:squiggle at:rect inContext:context];
}
- (void)drawSquiggle:(Squiggle *)squiggle at:(CGRect) rect inContext:(CGContextRef)context
{
CGContextSetBlendMode(context, kCGBlendModeMultiply);
UIColor *squiggleColor = squiggle.strokeColor; // get squiggle's color
CGColorRef colorRef = [squiggleColor CGColor]; // get the CGColor
CGContextSetStrokeColorWithColor(context, colorRef);
NSMutableArray *points = [squiggle points]; // get points from squiggle
// retrieve the NSValue object and store the value in firstPoint
CGPoint firstPoint; // declare a CGPoint
[[points objectAtIndex:0] getValue:&firstPoint];
// move to the point
CGContextMoveToPoint(context, firstPoint.x, firstPoint.y);
// draw a line from each point to the next in order
for (int i = 1; i < [points count]; i++)
{
NSValue *value = [points objectAtIndex:i]; // get the next value
CGPoint point; // declare a new point
[value getValue:&point]; // store the value in point
// draw a line to the new point
CGContextAddLineToPoint(context, point.x, point.y);
} // end for
CGContextStrokePath(context);
}
I try to implement this but seems it doesn't work as my expected. I have implemented a view to draw an square every time setNeedsDisplay is called on the view. I put CGImageRef image and CGBitmapContextRef context into ivar and allocate them when the view inits.
#import "View.h"
@implementation View
#define bitsPerComponent 8
#define bitsPerPixel 4*bitsPerComponent
#define bytesPerPixel 4
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
lastPoint = CGPointMake(50, 50);
size_t width = frame.size.width;
size_t height = frame.size.height;
CFMutableDataRef data = CFDataCreateMutable( NULL , width * height * bytesPerPixel );
CGDataProviderRef provider = CGDataProviderCreateWithCFData( data );
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
/*CGImageRef - ivar */ image = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, width*bytesPerPixel, colorspace, kCGImageAlphaPremultipliedLast, provider, NULL, NO, kCGRenderingIntentDefault);
/*CGBitmapContextRef - ivar */ context = CGBitmapContextCreate(CFDataGetMutableBytePtr(data), width, height, bitsPerComponent, width*bytesPerPixel , colorspace, kCGImageAlphaPremultipliedLast);
CFRelease( data 开发者_运维问答); // retained by provider I think
CGDataProviderRelease( provider ); // retained by image
CGColorSpaceRelease(colorspace);
}
return self;
}
- (void)drawRect:(CGRect)rect {
NSLog(@"test");
CGContextSetFillColorWithColor(context, [[UIColor blueColor] CGColor]);
CGContextFillRect(context, CGRectMake(lastPoint.x, lastPoint.y, 100, 100));
lastPoint = CGPointMake( ((int)lastPoint.x+50) % 380 , ((int)lastPoint.y+50) % 220 );
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, 100, 100),image);
}
- (void)dealloc {
[super dealloc];
}
@end
The graphics context returned by UIGraphicsGetCurrentContext
in drawRect:
is owned by the system and cleared at the start of a drawing pass. Create your own CGContext
to record your drawing and render it to the drawRect:
context as needed.
Create a paired CGBitmapContext
and CGImage
that refer to the same CGDataProvider
and have the same size, color space and other properties. Draw into that context when and how you see fit, then in drawRect:
use CGContextDrawImage
to display it.
Or if you are just doing a series of lines, you can build a CGMutablePath
and render it to the system context.
Edit:
Look at CGImageCreate
and CGBitmapContextCreate
in their respective header files. Most of the arguments are the same. The bitmap context expects a raw data pointer, while the image expects a CGDataProvider. Here is a rough sketch of what the code would look like. In the end you can draw into the context then use the image to render into another context.
size_t width = 400;
size_t height = 300;
CFMutableDataRef data = CFDataCreateMutable( NULL , width * height * 4 ); // 4 is bytes per pixel
CGDataProviderRef provider = CGDataProviderCreateWithCFData( data );
CGImageRef image = CGImageCreate( width , height , ... , provider , ... );
CGBitmapContextRef context = CGBitmapContextCreate( CFDataGetMutableBytePtr( data ) , width , height , ... );
CFRelease( data ); // retained by provider I think
CGDataProviderRelease( provider ); // retained by image
There are a lot of blanks to fill in, but this should get you started. You could use malloc instead of CFData for the buffer.
精彩评论