iPhone循环进度指示器。CGContextRef。按需提款
我想画一幅图像,它实际上是UIButton上的一个圆形进度指示器。因为图像应该表示任务的进度,所以我不认为应该在视图的drawrect方法中处理绘图代码 我有一个线程正在执行一些任务。在每个任务之后,它在主线程上调用一个方法。被调用的方法应该更新按钮上的图像 在按钮更新方法中,我使用CGBitmapContextCreate创建了一个CGContextRef。 然后我使用按钮的框架来创建一个CGRect。 然后,我尝试使用我创建的上下文。 最后,我设置了显示和清理需求 但这些都不在视图的drawrect方法中 我想知道是否有人在显示视图时使用CGContext在视图中按需绘制视图 我想得到一些关于这样做的方法的想法iPhone循环进度指示器。CGContextRef。按需提款,iphone,uibutton,progress,Iphone,Uibutton,Progress,我想画一幅图像,它实际上是UIButton上的一个圆形进度指示器。因为图像应该表示任务的进度,所以我不认为应该在视图的drawrect方法中处理绘图代码 我有一个线程正在执行一些任务。在每个任务之后,它在主线程上调用一个方法。被调用的方法应该更新按钮上的图像 在按钮更新方法中,我使用CGBitmapContextCreate创建了一个CGContextRef。 然后我使用按钮的框架来创建一个CGRect。 然后,我尝试使用我创建的上下文。 最后,我设置了显示和清理需求 但这些都不在视图的draw
/**
ArcImageCreate
@ingroup UngroupedFunctions
@brief Create a filled or unfilled solid arc and return it as a UIImage.
Allows for dynamic / arbitrary update of an object that allows a UIImage to be drawn on it. \
This can be used for some sort of pie chart or progress indicator by Image Flipping.
@param fHeight The height of the created UIImage.
@param fWidth The width of the created UIImage.
@param fPercentFilled A percentage of the circle to be filled by the arc. 0.0 to 1.0.
@param AngleStart The angle where the arc should start. 0 to 360. Clock Reference.
@param xFillColor The color of the filled area.
@return Pointer to a UIImage.
@todo [] Validate object creation at each step.
@todo [] Convert PercentFilled (0.0 to 1.0) to appropriate radian(?) (-3.15 to +3.15)
@todo [] Background Image Support. Allow for the arc to be drawn on top of an image \
and the whole thing returned.
@todo [] Background Image Reduction. Background images will have to be resized to fit the specfied size. \
Do not want to return a 65KB object because the background is 60K or whatever.
@todo [] UIColor RGBA Components. Determine a decent method of extracting RGVA values \
from a UIColor*. Check out arstechnica.com/apple/guides/2009/02/iphone-development-accessing-uicolor-components.ars \
for an idea.
*/
- (UIImage*) ArcImageCreate: (float)fHeight fWidth:(float)fWidth fPercentFilled:(float)fPercentFilled fAngleStart:(float)fAngleStart xFillColor:(UIColor*)xFillColor
{
UIImage* fnRez = nil;
float fArcBegin = 0.0f;
float fArcEnd = 0.0f;
float fArcPercent = 0.0f;
UIColor* xArcColor = nil;
float fArcImageWidth = 0.0f;
float fArcImageHeight = 0.0f;
CGRect xArcImageRect;
CGContextRef xContext = nil;
CGColorSpaceRef xColorSpace;
void* xBitmapData;
int iBMPByteCount;
int iBMPBytesPerRow;
float fPI = 3.14159;
float fRadius = 25.0f;
// @todo Force default of 100x100 px if out of bounds. \
// Check max image dimensions for iPhone. \
// If negative, flip values *if* values are 'reasonable'. \
// Determine minimum useable pixel dimensions. 10x10 px is too small. Or is it?
fArcImageWidth = fHeight;
fArcImageHeight = fWidth;
// Get the passed target percentage and clip it between 0.0 and 1.0
fArcPercent = (fPercentFilled 1.0f) ? 1.0f : fPercentFilled;
fArcPercent = (fArcPercent > 1.0f) ? 1.0f : fArcPercent;
// Get the passed start angle and clip it between 0.0 to 360.0
fArcBegin = (fAngleStart 359.0f) ? 0.0f : fAngleStart;
fArcBegin = (fArcBegin > 359.0f) ? 0.0f : fArcBegin;
fArcBegin = (fArcBegin * fPI) / 180.0f;
fArcEnd = ((360.0f * fArcPercent) * fPI) / 180.0f;
//
if (xFillColor == nil) {
// random color
} else {
xArcColor = xFillColor;
}
// Calculate memory required for image.
iBMPBytesPerRow = (fArcImageWidth * 4);
iBMPByteCount = (iBMPBytesPerRow * fArcImageHeight);
xBitmapData = malloc(iBMPByteCount);
// Create a color space. Behavior changes at OSXv10.4. Do not rely on it for consistency across devices.
xColorSpace = CGColorSpaceCreateDeviceRGB();
// Set the system to draw. Behavior changes at OSXv10.3.
// Both of these work. Not sure which is better.
// xContext = CGBitmapContextCreate(xBitmapData, fArcImageWidth, fArcImageHeight, 8, iBMPBytesPerRow, xColorSpace, kCGImageAlphaPremultipliedFirst);
xContext = CGBitmapContextCreate(NULL, fArcImageWidth, fArcImageHeight, 8, iBMPBytesPerRow, xColorSpace, kCGImageAlphaPremultipliedFirst);
// Let the system know the colorspace reference is no longer required.
CGColorSpaceRelease(xColorSpace);
// Set the created context as the current context.
// UIGraphicsPushContext(xContext);
// Define the image's box.
xArcImageRect = CGRectMake(0.0f, 0.0f, fArcImageWidth, fArcImageHeight);
// Clear the image's box.
// CGContextClearRect(xContext, xRect);
// Draw the ArcImage's background image.
// CGContextDrawImage(xContext, xArcImageRect, [oBackgroundImage CGImage]);
// Set Us Up The Transparent Drawing Area.
CGContextBeginTransparencyLayer(xContext, nil);
// Set the fill and stroke colors
// @todo [] Determine why SetFilColor does not. Use alternative method.
// CGContextSetFillColor(xContext, CGColorGetComponents([xArcColor CGColor]));
// CGContextSetFillColorWithColor(xContext, CGColorGetComponents([xArcColor CGColor]));
// Test Colors
CGContextSetRGBFillColor(xContext, 0.3f, 0.4f, 0.5f, 1.0f);
CGContextSetRGBStrokeColor(xContext, 0.5f, 0.6f, 0.7f, 1.0f);
CGContextSetLineWidth(xContext, 1.0f);
// Something like this to reverse drawing?
// CGContextTranslateCTM(xContext, TranslateXValue, TranslateYValue);
// CGContextScaleCTM(xContext, -1.0f, 1.0f); or CGContextScaleCTM(xContext, 1.0f, -1.0f);
// Test Vals
// fArcBegin = 45.0f * fPI / 180.0f; // 0.785397
// fArcEnd = 90.0f * fPI / 180.0f; // 1.570795
// Move to the start point and draw the arc.
CGContextMoveToPoint(xContext, fArcImageWidth/2.0f, fArcImageHeight/2.0f);
CGContextAddArc(xContext, fArcImageWidth/2.0f, fArcImageHeight/2.0f, fRadius, fArcBegin, fArcEnd, 0);
// Ask the OS to close the arc (current point to starting point).
CGContextClosePath(xContext);
// Fill 'er up. Implicit path closure.
CGContextFillPath(xContext);
// CGContextEOFillPath(context);
// Close Transparency drawing area.
CGContextEndTransparencyLayer(xContext);
// Create an ImageReference and create a UIImage from it.
CGImageRef xCGImageTemp = CGBitmapContextCreateImage(xContext);
CGContextRelease(xContext);
fnRez = [UIImage imageWithCGImage: xCGImageTemp];
CGImageRelease(xCGImageTemp);
// UIGraphicsPopContext;
return fnRez;
}
下面是我现在所做工作的一个封装版本:
CGContextRef xContext=nil;
CGCOLORSPACTEREF xColorSpace;
CGRect-xRect;
void*xBitmapData;
int IBMByteCount;
int IBMBytesperrow;
浮动fBMPWidth=20.0f;
浮动FBMPH高度=20.0f;
浮点数fPI=3.14159;
浮球弗雷迪乌斯=25.0f
iBMPBytesPerRow = (fBMPWidth * 4);
iBMPByteCount = (iBMPBytesPerRow * fBMPHeight);
xColorSpace = CGColorSpaceCreateDeviceRGB();
xBitmapData = malloc(iBMPByteCount);
xContext = CGBitmapContextCreate(xBitmapData, fBMPWidth, fBMPHeight, 8, iBMPBytesPerRow, xColorSpace, kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(xColorSpace);
UIGraphicsPushContext(xContext);
xRect = CGRectMake(30.0f, 400.0f, 50.0f, 50.0f);
float fWidth = xRect.size.width;
float fHeight = xRect.size.height;
CGContextClearRect(xContext, xRect);
CGContextSetRGBStrokeColor(xContext, 0.5f, 0.6f, 0.7f, 1.0f);
CGContextSetLineWidth(xContext, 1.0f);
float fArcBegin = 45.0f * fPI / 180.0f;
float fArcEnd = 90.0f * fPI / 180.0f;
CGContextSetFillColor(xContext, CGColorGetComponents( [[UIColor greenColor] CGColor]));
CGContextMoveToPoint(xContext, fWidth, fHeight);
CGContextAddArc(xContext, fWidth, fHeight, fRadius, fArcBegin, fArcEnd, 0);
CGContextClosePath(xContext);
CGContextFillPath(xContext);
UIGraphicsPopContext;
CGContextRelease(xContext);
[self.view setNeedsDisplay];
//[self.view setNeedsDisplayInRect:xRect]
上面的内容有点不可靠,因为我尝试了不同的调整。但是,我认为它传达了我正在尝试做的事情。替代方法:
您可以创建一系列表示进度更新的图像,然后在流程的每个步骤用setImage:forState:方法替换UIButton currentImage属性。这不需要在现有视图中绘制,这种方法对于我显示简单的图像“动画”(按钮或其他)非常有效
这种方法对你有用吗?若否,原因为何
Bart这真的让我很烦,所以在处理了一系列关于我想要这个功能的项目的愚蠢但必要的问题后,我就开始玩它了。 最终的结果是,我现在可以任意画一个弧,表示一个特定背景任务的进度到一个按钮 目标是在清理或编译项目时,在XCode窗口的右下角绘制类似于小指示器的东西 我创建了一个函数,它将绘制和填充圆弧,并将其作为UIImage返回 工作线程使用当前值和按钮标识符调用方法(PerformSelectorOnMainThread)。在调用的方法中,我调用带有填充百分比等的arc image函数 示例调用:
oImg = [self ArcImageCreate:100.0f fWidth:100.0f
fPercentFilled: 0.45f fAngleStart: 0.0f xFillColor:[UIColor blueColor]];
然后设置按钮的背景图像:
[oBtn setBackgroundImage: oImg forState: UIControlStateNormal];
下面是函数:它还没有完成,但它工作得很好,足以说明我是如何做到这一点的
/**
ArcImageCreate
@ingroup UngroupedFunctions
@brief Create a filled or unfilled solid arc and return it as a UIImage.
Allows for dynamic / arbitrary update of an object that allows a UIImage to be drawn on it. \
This can be used for some sort of pie chart or progress indicator by Image Flipping.
@param fHeight The height of the created UIImage.
@param fWidth The width of the created UIImage.
@param fPercentFilled A percentage of the circle to be filled by the arc. 0.0 to 1.0.
@param AngleStart The angle where the arc should start. 0 to 360. Clock Reference.
@param xFillColor The color of the filled area.
@return Pointer to a UIImage.
@todo [] Validate object creation at each step.
@todo [] Convert PercentFilled (0.0 to 1.0) to appropriate radian(?) (-3.15 to +3.15)
@todo [] Background Image Support. Allow for the arc to be drawn on top of an image \
and the whole thing returned.
@todo [] Background Image Reduction. Background images will have to be resized to fit the specfied size. \
Do not want to return a 65KB object because the background is 60K or whatever.
@todo [] UIColor RGBA Components. Determine a decent method of extracting RGVA values \
from a UIColor*. Check out arstechnica.com/apple/guides/2009/02/iphone-development-accessing-uicolor-components.ars \
for an idea.
*/
- (UIImage*) ArcImageCreate: (float)fHeight fWidth:(float)fWidth fPercentFilled:(float)fPercentFilled fAngleStart:(float)fAngleStart xFillColor:(UIColor*)xFillColor
{
UIImage* fnRez = nil;
float fArcBegin = 0.0f;
float fArcEnd = 0.0f;
float fArcPercent = 0.0f;
UIColor* xArcColor = nil;
float fArcImageWidth = 0.0f;
float fArcImageHeight = 0.0f;
CGRect xArcImageRect;
CGContextRef xContext = nil;
CGColorSpaceRef xColorSpace;
void* xBitmapData;
int iBMPByteCount;
int iBMPBytesPerRow;
float fPI = 3.14159;
float fRadius = 25.0f;
// @todo Force default of 100x100 px if out of bounds. \
// Check max image dimensions for iPhone. \
// If negative, flip values *if* values are 'reasonable'. \
// Determine minimum useable pixel dimensions. 10x10 px is too small. Or is it?
fArcImageWidth = fHeight;
fArcImageHeight = fWidth;
// Get the passed target percentage and clip it between 0.0 and 1.0
fArcPercent = (fPercentFilled 1.0f) ? 1.0f : fPercentFilled;
fArcPercent = (fArcPercent > 1.0f) ? 1.0f : fArcPercent;
// Get the passed start angle and clip it between 0.0 to 360.0
fArcBegin = (fAngleStart 359.0f) ? 0.0f : fAngleStart;
fArcBegin = (fArcBegin > 359.0f) ? 0.0f : fArcBegin;
fArcBegin = (fArcBegin * fPI) / 180.0f;
fArcEnd = ((360.0f * fArcPercent) * fPI) / 180.0f;
//
if (xFillColor == nil) {
// random color
} else {
xArcColor = xFillColor;
}
// Calculate memory required for image.
iBMPBytesPerRow = (fArcImageWidth * 4);
iBMPByteCount = (iBMPBytesPerRow * fArcImageHeight);
xBitmapData = malloc(iBMPByteCount);
// Create a color space. Behavior changes at OSXv10.4. Do not rely on it for consistency across devices.
xColorSpace = CGColorSpaceCreateDeviceRGB();
// Set the system to draw. Behavior changes at OSXv10.3.
// Both of these work. Not sure which is better.
// xContext = CGBitmapContextCreate(xBitmapData, fArcImageWidth, fArcImageHeight, 8, iBMPBytesPerRow, xColorSpace, kCGImageAlphaPremultipliedFirst);
xContext = CGBitmapContextCreate(NULL, fArcImageWidth, fArcImageHeight, 8, iBMPBytesPerRow, xColorSpace, kCGImageAlphaPremultipliedFirst);
// Let the system know the colorspace reference is no longer required.
CGColorSpaceRelease(xColorSpace);
// Set the created context as the current context.
// UIGraphicsPushContext(xContext);
// Define the image's box.
xArcImageRect = CGRectMake(0.0f, 0.0f, fArcImageWidth, fArcImageHeight);
// Clear the image's box.
// CGContextClearRect(xContext, xRect);
// Draw the ArcImage's background image.
// CGContextDrawImage(xContext, xArcImageRect, [oBackgroundImage CGImage]);
// Set Us Up The Transparent Drawing Area.
CGContextBeginTransparencyLayer(xContext, nil);
// Set the fill and stroke colors
// @todo [] Determine why SetFilColor does not. Use alternative method.
// CGContextSetFillColor(xContext, CGColorGetComponents([xArcColor CGColor]));
// CGContextSetFillColorWithColor(xContext, CGColorGetComponents([xArcColor CGColor]));
// Test Colors
CGContextSetRGBFillColor(xContext, 0.3f, 0.4f, 0.5f, 1.0f);
CGContextSetRGBStrokeColor(xContext, 0.5f, 0.6f, 0.7f, 1.0f);
CGContextSetLineWidth(xContext, 1.0f);
// Something like this to reverse drawing?
// CGContextTranslateCTM(xContext, TranslateXValue, TranslateYValue);
// CGContextScaleCTM(xContext, -1.0f, 1.0f); or CGContextScaleCTM(xContext, 1.0f, -1.0f);
// Test Vals
// fArcBegin = 45.0f * fPI / 180.0f; // 0.785397
// fArcEnd = 90.0f * fPI / 180.0f; // 1.570795
// Move to the start point and draw the arc.
CGContextMoveToPoint(xContext, fArcImageWidth/2.0f, fArcImageHeight/2.0f);
CGContextAddArc(xContext, fArcImageWidth/2.0f, fArcImageHeight/2.0f, fRadius, fArcBegin, fArcEnd, 0);
// Ask the OS to close the arc (current point to starting point).
CGContextClosePath(xContext);
// Fill 'er up. Implicit path closure.
CGContextFillPath(xContext);
// CGContextEOFillPath(context);
// Close Transparency drawing area.
CGContextEndTransparencyLayer(xContext);
// Create an ImageReference and create a UIImage from it.
CGImageRef xCGImageTemp = CGBitmapContextCreateImage(xContext);
CGContextRelease(xContext);
fnRez = [UIImage imageWithCGImage: xCGImageTemp];
CGImageRelease(xCGImageTemp);
// UIGraphicsPopContext;
return fnRez;
}
你不使用UIActivityIndicatorView有什么原因吗?DC:有。我希望像使用UIProgressView一样显示任务进度。我不想像UIActivityIndicatorView那样展示正在发生的事情。嗨,巴特,这是我在无法实现最初想法后实现的。我希望图像旋转的实现是暂时的,但我接受它可能是永久的。