Я сделал весь рабочий пакет, который будет имитировать этот прогресс, который вы опубликовали. Однако, чтобы сделать его более настраиваемым, я не использовал никаких изображений, но использовал CoreGraphics для его рисования. Пакет можно найти по адресу: lightdesign/LDProgressView. Я также, вероятно, сделаю это в CocoaPod, если вы знаете, что это такое.
Как рисовать байдарку типа Прогресс Просмотр
Все внутренние работы зрения прогресса и, следовательно, как имитировать вид прогресса каяк можно найти в this file. Я добавил несколько комментариев здесь, в блоках кода, для более легкого понимания. Вот drawRect
метод:
- (void)drawRect:(CGRect)rect {
[self setAnimateIfNotSet];
CGContextRef context = UIGraphicsGetCurrentContext();
[self drawProgressBackground:context inRect:rect];
if (self.progress > 0) {
[self drawProgress:context withFrame:rect];
}
}
Это довольно очевидно. Я установил свойство animate, если оно уже не установлено, и я рисую фон. Тогда, если прогресс будет больше 0, я нарисую прогресс в общем фрейме. Давайте перейдем к методу drawProgressBackground:inRect:
:
- (void)drawProgressBackground:(CGContextRef)context inRect:(CGRect)rect {
CGContextSaveGState(context);
// Draw the background with a gray color within a rounded rectangle
UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:10];
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:0.51f green:0.51f blue:0.51f alpha:1.00f].CGColor);
[roundedRect fill];
// Create the inner shadow path
UIBezierPath *roundedRectangleNegativePath = [UIBezierPath bezierPathWithRect:CGRectMake(-10, -10, rect.size.width+10, rect.size.height+10)];
[roundedRectangleNegativePath appendPath:roundedRect];
roundedRectangleNegativePath.usesEvenOddFillRule = YES;
CGSize shadowOffset = CGSizeMake(0.5, 1);
CGContextSaveGState(context);
CGFloat xOffset = shadowOffset.width + round(rect.size.width);
CGFloat yOffset = shadowOffset.height;
CGContextSetShadowWithColor(context,
CGSizeMake(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset)), 5, [[UIColor blackColor] colorWithAlphaComponent:0.7].CGColor);
// Draw the inner shadow
[roundedRect addClip];
CGAffineTransform transform = CGAffineTransformMakeTranslation(-round(rect.size.width), 0);
[roundedRectangleNegativePath applyTransform:transform];
[[UIColor grayColor] setFill];
[roundedRectangleNegativePath fill];
CGContextRestoreGState(context);
}
Здесь я создаю прямоугольник с закругленными углами в пределах вида с радиусом 10
(который я впоследствии может позволить быть настраиваемым) и заполнить его. Затем остальная часть кода рисует внутреннюю тень, о которой мне не нужно подробно останавливаться. Теперь, вот код для рисования прогресса в методе drawProgress:withFrame:
:
- (void)drawProgress:(CGContextRef)context withFrame:(CGRect)frame {
CGRect rectToDrawIn = CGRectMake(0, 0, frame.size.width * self.progress, frame.size.height);
CGRect insetRect = CGRectInset(rectToDrawIn, 0.5, 0.5);
UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:insetRect cornerRadius:10];
if ([self.flat boolValue]) {
CGContextSetFillColorWithColor(context, self.color.CGColor);
[roundedRect fill];
} else {
CGContextSaveGState(context);
[roundedRect addClip];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[] = {0.0, 1.0};
NSArray *colors = @[(__bridge id)[self.color lighterColor].CGColor, (__bridge id)[self.color darkerColor].CGColor];
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colors, locations);
CGContextDrawLinearGradient(context, gradient, CGPointMake(insetRect.size.width/2, 0), CGPointMake(insetRect.size.width/2, insetRect.size.height), 0);
CGContextRestoreGState(context);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
CGContextSetStrokeColorWithColor(context, [[self.color darkerColor] darkerColor].CGColor);
[self drawStripes:context inRect:insetRect];
[roundedRect stroke];
[self drawRightAlignedLabelInRect:insetRect];
}
Есть 4 первичные частей к этому методу. Во-первых, я вычисляю фрейм, что прогресс будет зависеть от свойства self.progress
. Во-вторых, я рисую сплошной цвет, если установлено свойство flat
, или я рисую градиент (методы lighterColor
и darkerColor
относятся к категории UIColor
). В-третьих, я рисую полосы и, наконец, рисую процентную метку. Давайте рассмотрим эти 2 метода быстро. Вот метод:
- (void)drawStripes:(CGContextRef)context inRect:(CGRect)rect {
CGContextSaveGState(context);
[[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:10] addClip];
CGContextSetFillColorWithColor(context, [[UIColor whiteColor] colorWithAlphaComponent:0.2].CGColor);
CGFloat xStart = self.offset, height = rect.size.height, width = STRIPE_WIDTH;
while (xStart < rect.size.width) {
CGContextSaveGState(context);
CGContextMoveToPoint(context, xStart, height);
CGContextAddLineToPoint(context, xStart + width * 0.25, 0);
CGContextAddLineToPoint(context, xStart + width * 0.75, 0);
CGContextAddLineToPoint(context, xStart + width * 0.50, height);
CGContextClosePath(context);
CGContextFillPath(context);
CGContextRestoreGState(context);
xStart += width;
}
CGContextRestoreGState(context);
}
Это где анимация «магия» происходит. По существу, я рисую эти полосы на основе self.offset
, который находится где-то между -STRIPE_WIDTH
и 0
с увеличением по таймеру. Затем я создаю простой цикл, так что я создаю достаточно полосок, чтобы полностью заполнить часть прогресса представления. Я также оставляю 25% пустого STRIPE_WIDTH
, так что полосы не скреплены друг с другом.Вот последний метод рисования drawRightAlignedLabelInRect:
:
- (void)drawRightAlignedLabelInRect:(CGRect)rect {
UILabel *label = [[UILabel alloc] initWithFrame:rect];
label.backgroundColor = [UIColor clearColor];
label.textAlignment = NSTextAlignmentRight;
label.text = [NSString stringWithFormat:@"%.0f%%", self.progress*100];
label.font = [UIFont boldSystemFontOfSize:17];
UIColor *baseLabelColor = [self.color isLighterColor] ? [UIColor blackColor] : [UIColor whiteColor];
label.textColor = [baseLabelColor colorWithAlphaComponent:0.6];
[label drawTextInRect:CGRectOffset(rect, -6, 0)];
}
В этом методе я создаю ярлык с текстом, который преобразует с плавающей точкой (между 0.0
и 1.0
) в процентах (от 0%
до 100%
). Затем я либо устанавливаю, чтобы цвет был темным или светлым, в зависимости от темноты выбранного цвета хода и рисовал ярлык в CGContext
.
Customizability
Есть три свойства, которые могут быть установлены либо непосредственно на экземпляре LDProgressView
или заранее в методе UIAppearance
.
цвет будет, очевидно, установить общий вид сборщика. Из этого определяются градиенты, полосы и/или контурные цвета. Метод UIAppearance
будет что-то вроде этого:
[[LDProgressView appearance] setColor:[UIColor colorWithRed:0.87f green:0.55f blue:0.09f alpha:1.00f]];
Это позволит определить, является ли фон с точки зрения прогресса будет градиент или просто color
свойство. Этот UIAppearance
метод будет выглядеть примерно так:
[[LDProgressView appearance] setFlat:@NO];
Наконец, это будет определять, будут ли анимированные полосы. Этот UIAppearance
метод также может быть установлен в общем для всех экземпляров LDProgressView
и выглядит следующим образом:
[[LDProgressView appearance] setAnimate:@YES];
Заключение
Уф! Это был длинный ответ. Надеюсь, я не слишком утомлял вас, ребята. Если вы просто пропустили сюда, вот суть для рисования кода, а не с помощью изображений. Я думаю, что CoreGraphics - превосходный способ рисования на iOS, если у вас есть время/опыт, поскольку он позволяет настраивать больше, и я считаю, что он быстрее.
Вот картина окончательного, рабочий продукт:
![LDProgressView](https://dl.dropboxusercontent.com/u/20180054/Github%20Resources/LD-progress-view-improved.png)
Посмотрите на - (UIImage *) resizableImageWithCapInsets: (UIEdgeInsets) capInsets. Это с любым из предложений github должно быть работоспособным. – EricLeaf