如何制作像KAYAK应用程序中的进度视图

JAH*_*lia 3 iphone objective-c uiprogressview ios

我想知道如何制作一个看起来像KAYAK应用程序中的进度视图(这是一个搜索航班和酒店的旅行应用程序),截图:

在此输入图像描述

我在越狱的iPhone上挖掘了KAYAK应用程序的资源,发现以下3个构建此进度视图的图像:

progressbar-background@2x.png

在此输入图像描述

progressbar-gradient@2x.png

在此输入图像描述

progressbar-overlay@2x.png

在此输入图像描述

假设进度视图具有与梯度图像一起重复移动的移动叠加图像.

任何想法或示例代码将受到高度赞赏.

Chr*_*nzo 7

我制作了完整的工作包,模仿你发布的这个进度视图.但是,为了使其更具可定制性,我没有使用任何图像,而是使用CoreGraphics来绘制它.该软件包可以在lightdesign/LDProgressView中找到.如果你知道那是什么,我也可能把它变成一个CocoaPod.

如何绘制类似KAYAK的进度视图

可以在此文件中找到进度视图的所有内部工作方式以及如何模拟KAYAK进度视图.为了便于理解,我在代码块中添加了一些注释.这是drawRect方法:

- (void)drawRect:(CGRect)rect {
    [self setAnimateIfNotSet];
    CGContextRef context = UIGraphicsGetCurrentContext();
    [self drawProgressBackground:context inRect:rect];
    if (self.progress > 0) {
        [self drawProgress:context withFrame:rect];
    }
}
Run Code Online (Sandbox Code Playgroud)

这是非常明显的.我设置了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);
}
Run Code Online (Sandbox Code Playgroud)

在这里,我在视图中创建一个圆角矩形,其半径为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];
}
Run Code Online (Sandbox Code Playgroud)

这种方法有4个主要部分.首先,我根据self.progress属性计算进度将占用的帧.其次,如果flat设置了属性,我绘制一个纯色,或者我绘制一个计算的渐变(方法lighterColordarkerColor在一个UIColor类别中).第三,我绘制条纹,最后绘制百分比标签.让我们快速介绍这两种方法.这是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);
}
Run Code Online (Sandbox Code Playgroud)

这就是动画"神奇"发生的地方.基本上我绘制基于关的这些条纹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)];
}
Run Code Online (Sandbox Code Playgroud)

在这个方法中,我创建了一个带有文本的标签,该标签从float(在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]];
Run Code Online (Sandbox Code Playgroud)
  • 平面

这将确定进度视图的背景是梯度还是仅color属性.这个UIAppearance方法看起来像这样:

[[LDProgressView appearance] setFlat:@NO];
Run Code Online (Sandbox Code Playgroud)
  • 活跃

最后,这将确定条纹是否会被动画化.UIAppearance也可以为所有实例设置此方法LDProgressView,如下所示:

[[LDProgressView appearance] setAnimate:@YES];
Run Code Online (Sandbox Code Playgroud)

结论

呼!这是一个很长的答案.我希望我没有给你们太多的鼓励.如果你刚刚跳到这里,这里是用于绘制代码而不是图像的要点.我认为CoreGraphics是一种优秀的iOS绘图方式,如果你有时间/经验,因为它允许更多的自定义,我相信往往会更快.

这是最终的工作产品图片:

LDProgressView