Один быстрый и грязный трюк - добавить слой градиента в качестве подслоя, а затем добавить еще несколько слоев с цветами фона, такими же, как у суперпредставления (в исходном вопросе он белый).
Например:
- Добавьте слой градиента (и установите правильный
cornerRadius
).
![заполненный градиентный слой](https://i.stack.imgur.com/ySKWi.png)
- Добавьте слой меньшего размера с белым фоном в центре слоя с градиентом (это создаст кольцо).
а>
- Создайте небольшой сегмент дуги с белым цветом фона.
![кольцо с зазором](https://i.stack.imgur.com/7sbea.png)
Однако это может не подходить для просмотра с фоновыми изображениями. Чтобы решить эту проблему, вы можете создать собственный подкласс UIView
и переопределить метод drawRect
.
Предположим, что есть переменные экземпляра: startColor
, endColor
, radius
, strokeWidth
и mirrored
.
Переменная mirrored
используется для управления положением промежутка (отрезанная левая сторона или правая сторона) и направлением вращения анимации (по часовой стрелке или против часовой стрелки).
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(ctx, kCGBlendModeNormal);
CGFloat gradientColors[4 * 2];
extractColorComponents(_startColor, gradientColors, 0);
extractColorComponents(_endColor, gradientColors, 4);
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, gradientColors, NULL, 2);
CGColorSpaceRelease(baseSpace);
baseSpace = nil;
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint, 0);
CGGradientRelease(gradient);
gradient = nil;
// fill 'clear' color
CGContextSetFillColorWithColor(ctx, [UIColor clearColor].CGColor);
CGContextSetStrokeColorWithColor(ctx, [UIColor clearColor].CGColor);
CGContextSetBlendMode(ctx, kCGBlendModeClear);
CGFloat innerCircleRadius = _radius - _strokeWidth;
// fill an 'empty' hole inside the gradient part
CGContextFillEllipseInRect(ctx, (CGRect){
{_strokeWidth, _strokeWidth},
{innerCircleRadius * 2, innerCircleRadius * 2}
});
// fill an 'empty' segment of arc
CGFloat startAngle = _mirrored ? (0.9 * M_PI) : (-0.1 * M_PI);
CGFloat endAngle = startAngle + 0.2 * M_PI;
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:(CGPoint){_radius, _radius}
radius:_radius - _strokeWidth * 0.5
startAngle:startAngle
endAngle:endAngle
clockwise:YES];
path.lineWidth = _strokeWidth;
CGContextAddPath(ctx, path.CGPath);
CGContextSetLineWidth(ctx, _strokeWidth + 2);
CGContextStrokePath(ctx);
CGContextSetBlendMode(ctx, kCGBlendModeNormal);
}
Вот полная реализация представления.
Конечный результат:
![анимированный счетчик](https://i.stack.imgur.com/ulqGI.gif)
Два кольца:
Вы можете добавить два кольца в свой viewDidLoad
или куда-то еще с помощью следующего кода для достижения желаемого эффекта:
- (void)viewDidLoad
{
[super viewDidLoad];
UIColor *startColor = [UIColor colorWithHue:0.02 saturation:0.74 brightness:0.91 alpha:1];
UIColor *endColor = [UIColor colorWithHue:0.57 saturation:0.76 brightness:0.86 alpha:1];
CGPoint center = CGPointMake(160, 200);
Spinner *outerSpinner = [[Spinner alloc] initWithCenter:center
radius:50
strokeWidth:3
startColor:startColor
endColor:endColor
mirrored:NO];
Spinner *innerSpinner = [[Spinner alloc] initWithCenter:center
radius:40
strokeWidth:3
startColor:startColor
endColor:endColor
mirrored:YES];
[self.view addSubview:outerSpinner];
[self.view addSubview:innerSpinner];
[outerSpinner startAnimating];
[innerSpinner startAnimating];
}
Результат:
![двойные анимированные кольца](https://i.stack.imgur.com/LBk30.gif)
person
Cheng-Yu Hsu
schedule
28.11.2015