我需要一个派生自UIView
的类,它通过填充一个越来越大的圆圈来表示进度(当进度从0变为1时,它的角度应增加2 PI)。它就像是UIProgressView
的循环版本。
以下代码还没有完成这项工作:它产生了越来越多的小扇区,这些扇区以闪烁的斑马图案堆叠。据推测,代码正在弄乱其坐标与UIView flipping的坐标系,CGContextAddArc
(显然)反直觉定义为“顺时针”等等。
错误行为的原因是什么?如何解决?
#define PERCENTAGE_TO_RADIANS(PERCENTAGE) ((PERCENTAGE) * 2 * M_PI - M_PI_2)
- (void)drawRect:(CGRect)rect
{
NSAssert(!self.opaque, nil);
NSAssert(!self.clearsContextBeforeDrawing, nil);
CGSize size = self.bounds.size;
CGPoint center = [self.superview convertPoint:self.center toView:self];
NSAssert(size.width == size.height, nil);
NSAssert((self.progress >= 0) && (self.progress <= 1), nil);
NSAssert(PERCENTAGE_TO_RADIANS(0 ) == -M_PI_2 , nil); // 0% progress corresponds to north
NSAssert(PERCENTAGE_TO_RADIANS(0.25) == 0 , nil); // 25% progress corresponds to east
NSAssert(PERCENTAGE_TO_RADIANS(0.5 ) == M_PI_2 , nil); // 50% progress corresponds to south
NSAssert(PERCENTAGE_TO_RADIANS(0.75) == M_PI , nil); // 75% progress corresponds to west
NSAssert(PERCENTAGE_TO_RADIANS(1 ) == 3 * M_PI_2, nil); // 100% progress corresponds to north
CGFloat x = center.x;
CGFloat y = center.y;
CGFloat radius = size.width / 2.0;
CGFloat startAngle = self.lastAngle;
CGFloat endAngle = PERCENTAGE_TO_RADIANS(self.progress);
int clockwise = 0;
if (self.progress > 0) {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetFillColorWithColor(context, self.sectorTintColor.CGColor);
CGContextSetLineWidth(context, 1);
NSAssert(startAngle <= endAngle, nil);
CGContextMoveToPoint(context, x, y);
CGContextAddArc(context, x, y, radius, startAngle, endAngle, clockwise);
CGContextClosePath(context);
CGContextFillPath(context);
CGContextRestoreGState(context);
}
self.lastAngle = endAngle;
}
答案 0 :(得分:1)
您需要知道的最重要的事情是正Y向下,这使得角度和顺时针方向不直观。你有两个选择,要么只是随身携带,要么在绘制任何东西之前翻转Y轴。在下面的示例代码中,我采用了后一种方法。
drawRect
方法不是累积的。换句话说,您需要在每次调用drawRect
时绘制整个扇区。因此没有理由跟踪起始角度,你应该始终从角度PI / 2开始并绘制整个扇区。
无需保存和恢复图形状态。每次调用drawRect
时都会创建新的图形上下文。
UIColor类具有set
,setFill
和setStroke
方法,可让您在不使用CGColors的情况下更改填充和描边颜色。
考虑到所有这些,这就是代码的样子,假设self.progress
是介于0.0和1.0之间的数字
- (void)drawRect:(CGRect)rect
{
if ( self.progress <= 0 || self.progress > 1.0 )
return;
CGFloat x = self.bounds.size.width / 2.0;
CGFloat y = self.bounds.size.height / 2.0;
CGFloat r = (x <= y) ? x : y;
CGFloat angle = M_PI_2 - self.progress * 2.0 * M_PI;
CGContextRef context = UIGraphicsGetCurrentContext();
// fix the y axis, so that positive y is up
CGContextScaleCTM( context, 1.0, -1.0 );
CGContextTranslateCTM( context, 0, -self.bounds.size.height );
// draw the pie shape
[self.sectorTintColor setFill];
CGContextMoveToPoint( context, x, y );
CGContextAddArc( context, x, y, r, M_PI_2, angle, YES );
CGContextClosePath( context );
CGContextFillPath( context );
}