как сделать вид прогресса, как в приложении KAYAK
Интересно, как сделать вид прогресса, который выглядит как в приложении KAYAK (это приложение для поиска рейсов и отелей), скриншот:
Я покопался в ресурсах приложения KAYAK на взломанном iPhone и нашел следующие 3 изображения, которые строят это представление Прогресса:
Progressbar-background@2x.png
Progressbar-gradient@2x.png
Progressbar-overlay@2x.png
Дача что вид прогресса имеет движущиеся изображения наложения, которые перемещаются многократно вместе с изображением градиента.
Любые идеи или примеры кода будут высоко оценены.
8 ответов:
Я сделал весь рабочий пакет, который будет имитировать этот вид прогресса, который вы опубликовали. Однако, чтобы сделать его более настраиваемым, я не использовал никаких изображений, но использовал CoreGraphics, чтобы нарисовать его. Пакет можно найти по адресуlightdesign/LDProgressView . Я также, вероятно, превращу его вCocoaPod , Если вы знаете, что это такое.
Как нарисовать Каякоподобный вид прогресса
Все внутренние работы представления прогресса и, следовательно, как имитировать байдарку представление прогресса можно найти в этом файле. Я добавил некоторые комментарии здесь, в блоках кода, для облегчения понимания. Вот метод
drawRect
:Это довольно само собой разумеющееся. Я устанавливаю свойство animate, если оно еще не установлено, и рисую фон. Затем, если прогресс больше 0, Я нарисую прогресс в пределах общего кадра. Перейдем к методу- (void)drawRect:(CGRect)rect { [self setAnimateIfNotSet]; CGContextRef context = UIGraphicsGetCurrentContext(); [self drawProgressBackground:context inRect:rect]; if (self.progress > 0) { [self drawProgress:context withFrame:rect]; } }
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:
:Этот метод состоит из 4 основных частей. Во-первых, я делаю расчет фрейма, который займет прогресс, основываясь на свойстве- (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]; }
self.progress
. Во-вторых, я рисую либо сплошной цвет, если установлено свойствоflat
, либо вычисленный градиент (методыlighterColor
иdarkerColor
относятся к категорииUIColor
). В-третьих, я рисую полосы и, наконец, рисую процентную метку. Давайте быстро рассмотрим эти 2 метода. Вот методdrawStripes:inRect:
:- (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
.Настраиваемость
Есть три свойства, которые может быть установлен либо непосредственно на экземпляре
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, Если у вас есть время/опыт, так как он позволяет больше настройки, и я считаю, как правило, быстрее.
Вот изображение конечного, работающего продукта:
Вы можете использовать
NSTimer
для обновления "смещения", при котором вы начинаете визуализацию наложения. Вы можете найти пример здесь . Это OS X control, и он использует пользовательский рисунок, а не изображения, но принцип тот же.
Отрегулируйте цвет и толщину, и вы можете идти! https://www.cocoacontrols.com/controls/ylprogressbar
Этот тоже кажется хорошим... но я им еще не пользовался. https://github.com/JonasGessner/JGProgressView
Удачи!
Ближайшим связанным индикатором прогресса в вашем случае являетсяADVProgressBar .
Здесь вам нужно сделать небольшую модификацию. Например, вам нужно изменить изображение задней поверхности, и вы можете добавить эти закругленные углы. После этих изменений индикатор выполнения будет выглядеть точно так же, как вы упомянули в своем вопросе.
Скриншот:
Попробуйте элементы управления Cocoa для ProgressView....... что касается наложенных изображений, вам нужно использовать NSTimer, который ретранслирует в абсолютной синхронизации с progressview
Когда вы устанавливаете свой
UIProgressView
(self.progress
) нас следующие настройки, чтобы получить тот же вид:UIImage *mynd =[[UIImage imageNamed:@"KgcoJ.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(11, 13, 11, 13)]; UIImage *bakMynd =[[UIImage imageNamed:@"UoS0A.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(11, 13, 11, 13)]; [self.progress setProgressImage:mynd]; [self.progress setTrackImage:bakMynd];
Примечание возможно, вам придется изменить имена изображений и номера в
UIEdgeInsetsMake
в зависимости от размеров вашего изображения. Это даст вам следующее: