Quartz2D在项目中的实际使用

还记得大学刚学iOS那会,从学校图书馆借了本iOS开发的书,有一章节介绍了Quartz2D,当时看得一头雾水,感觉这画画线,画画圆有什么用呢🤔️?工作一段时间后,遇到了一些需求,终于可以把咸丰年学的Quartz2D知识拿出来用一用了💪。下面总结下这些年做项目用到Quartz2D的7个例子。

一.单纯画个圈。

有个项目要模仿呆萌价APP顶部轮播图,然后轮播图后面需要有个圆弧:
在这里插入图片描述
一看到这需求,不简单吗?找UI小姐姐切个圆弧图片就好啦😄。
但是细细一看。wtf🙀。圆弧颜色是随着轮播图一起改变的:
在这里插入图片描述
在这里插入图片描述
也就是圆弧会根据录播图的主色调而改变颜色,或许我们可以麻烦UI小姐姐提供多个颜色的切图。但是这样只能是有限个颜色值了。而且图片多了。。。还增加了包大小🤣🤣。
此时只要用Quartz2D,简单几句代码就解决问题啦,寥寥十几行代码还几乎不增加包大小。

1.新建HYBgView,继承View
2.重写drawRect:方法
-(void)drawRect:(CGRect)rect{
    CGContextRef context = UIGraphicsGetCurrentContext();
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(0, 0)];
    [path addLineToPoint:CGPointMake(0, 60)];
    [path addQuadCurveToPoint:CGPointMake(kScreenWidth, 60) controlPoint:CGPointMake(kScreenWidth*0.5, 120)];
    [path addLineToPoint:CGPointMake(kScreenWidth, 0)];
    [path closePath];
    
    CGContextAddPath(context, path.CGPath);
    CGContextSetFillColorWithColor(context, [UIColor colorWithHexString:self.hyColor].CGColor);
    CGContextFillPath(context);
}

其中hyColor是我们定义的HYBgView的属性,类型为UIColor:

@interface HYBgView : UIView

@property(nonatomic,strong) NSString *hyColor;

@end

3.重写hyColor的set方法,在修改颜色时让系统进行重绘:
-(void)setHyColor:(NSString *)hyColor{
    _hyColor = hyColor;
    [self setNeedsDisplay];
}
二.带透明窗口的引导图

在老东家太平洋网络做的项目,如下图的一键海报的新手指引图,需求是遮罩层中间有个镂空的矩形,把第一张海报显示出来,其它地方是50%透明度,当时最终实现效果如图:
在这里插入图片描述
我们通过UIBezierPath和CAShapeLayer绘制一张中间镂空(完全透明),其它部分50%透明的遮罩层。

1、新建类PCOnePosterGuide,继承UIView
2、重写drawRect:方法:
- (void)drawRect:(CGRect)rect {
  [super drawRect:rect];
  
  //整个view(如下图,蓝色部分,为方便解释上的颜色,实际效果为50%透明,下同)
  UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:0];
  
  //中间空的部分(如下图:粉红色部分,实际效果为镂空透明)
  UIBezierPath *maskPath;
  CGFloat maskW = (IOS_VERSION>=10.)?64.:50.;
  CGFloat padding = (SCREEN_WIDTH>375)?6.:2.;
  maskPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(SCREEN_WIDTH-maskW-padding, PCSTATUSBAR_HEIGHT+4, maskW, 36.)
                                   byRoundingCorners:UIRectCornerAllCorners
                                         cornerRadii:CGSizeMake(2, 2)];
  [path appendPath:maskPath];
  //使用奇偶性原则,设置填充部分为除去粉色的蓝色部分
  [path setUsesEvenOddFillRule:YES];
  
  CAShapeLayer *fillLayer = [CAShapeLayer layer];
  fillLayer.path = path.CGPath;
  fillLayer.fillRule = kCAFillRuleEvenOdd;
  fillLayer.fillColor = [UIColor blackColor].CGColor;
  fillLayer.opacity = 0.5;
  [self.layer addSublayer:fillLayer];  
}

为了方便解释,上的颜色,实际为透明
在这里插入图片描述

三、排序按钮

如图中的排序按钮(正序/倒序),完全使用Core Graphic进行绘制,可以方便地设置颜色、大小、字体等,而不需要找设计同事拿切图哦😊:
在这里插入图片描述
在这里插入图片描述
绘制代码:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    if (_title.length > 0) {
		//绘制文字
        CGSize textSize = [_title sizeForFont:[UIFont systemFontOfSize:14] size:CGSizeMake(200, 40) mode:NSLineBreakByClipping];
        CGFloat textW = textSize.width;
        CGFloat textH = textSize.height;
        UIColor *selectColor = self.selectColor?:[UIColor colorWithRed:137/255.0 green:67/255.0 blue:167/255.0 alpha:1.0];
        UIColor *unselectColor = self.unselectColor?:[UIColor colorWithRed:102/255.0 green:102/255.0 blue:102 /255.0 alpha:1.0];
        
        UIColor *textColor = self.type==HYRankTypeNone?unselectColor:selectColor;
        [_title drawInRect:CGRectMake((self.width-textW)/2.0, (self.height-textH)/2.0, textW, self.height) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14],NSForegroundColorAttributeName:textColor}];

        CGFloat triangleW = self.triangleW>0?self.triangleW:10;
        CGFloat trianglePadding = 4;

        //绘制上三角形
        if (self.type == HYRankTypeNone || self.type == HYRankTypeDown) {
            CGContextSetFillColorWithColor(context, unselectColor.CGColor);
        }else{
            CGContextSetFillColorWithColor(context, selectColor.CGColor);
        }

        CGFloat x1 = (self.width+textW)/2.0+trianglePadding+triangleW/2.0;
        CGFloat y1 = self.height/2.0 - triangleW/2.0 - 1;
        CGContextMoveToPoint(context, x1, y1);

        CGFloat x2 = x1+triangleW/2.0;
        CGFloat y2 = y1+triangleW/2.0;
        CGContextAddLineToPoint(context, x2, y2);

        CGFloat x3 = x1-triangleW/2.0;
        CGFloat y3 = y2;
        CGContextAddLineToPoint(context, x3, y3);

        CGContextClosePath(context);
        CGContextFillPath(context);

        //绘制下三角形
        if (self.type == HYRankTypeNone || self.type == HYRankTypeUp) {
            CGContextSetFillColorWithColor(context, unselectColor.CGColor);
        }else{
            CGContextSetFillColorWithColor(context, selectColor.CGColor);
        }

        CGFloat a1 = x1;
        CGFloat b1 = y1 + triangleW + 2;
        CGContextMoveToPoint(context, a1, b1);

        CGFloat a2 = x2;
        CGFloat b2 = y2 + 2;
        CGContextAddLineToPoint(context, a2, b2);

        CGFloat a3 = x3;
        CGFloat b3 = y3 + 2;
        CGContextAddLineToPoint(context, a3, b3);

        CGContextClosePath(context);
        CGContextFillPath(context);
    }
}

排序按钮我简单地封装到了HYRankView,完整代码及详细使用方法点我

4.继续画画:卡片背景

如图中的卡片背景,也是可以通过Quartz2D快速画出来,又为APP包大小立下功劳~
在这里插入图片描述
绘制代码:

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    //左边半圆
    UIBezierPath *leftPath = [UIBezierPath bezierPath];
    CGFloat y = 158;
    [leftPath addArcWithCenter:CGPointMake(0, y) radius:15 startAngle:3/2.0*M_PI endAngle:1/2.0*M_PI clockwise:YES];
    [leftPath closePath];
    CGContextAddPath(context, leftPath.CGPath);
    CGContextSetFillColorWithColor(context, UIColorHex(#F9F8FF).CGColor);
    CGContextFillPath(context);
    
    //右边半圆
    UIBezierPath *rightPath = [UIBezierPath bezierPath];
    CGFloat rightX = kScreenWidth-32;
    [rightPath addArcWithCenter:CGPointMake(rightX, y) radius:15 startAngle:3/2.0*M_PI endAngle:1/2.0*M_PI clockwise:NO];
    [rightPath closePath];
    CGContextAddPath(context, rightPath.CGPath);
    CGContextFillPath(context);

    //中间分割虚线
    CGContextMoveToPoint(context, 30, y);
    CGContextAddLineToPoint(context, kScreenWidth-32-30, y);
    CGContextSetLineWidth(context, 1);
    CGContextSetStrokeColorWithColor(context, UIColorHex(#666666).CGColor);
    CGFloat lengths[] = {3,3};
    CGContextSetLineDash(context, 0, lengths,2);
    CGContextDrawPath(context, kCGPathStroke);
}

5.贝塞尔曲线+动画

这个demo是业余模仿美人相机的,还没用到实际项目上。效果:
在这里插入图片描述
我的另一篇博客写的很详细了,这里就不再累赘:

贝塞尔曲线动画demo(仿美人相机效果)

6.环形进度条

如图。是设计姐姐给的下载进度设计图。
在这里插入图片描述
其实就只画两个圈,一个灰色的圆环和一个根据下载百分比动态变化的黄色圆环。代码:

-(void)drawRect:(CGRect)rect{
    CGContextRef ctx = UIGraphicsGetCurrentContext();//获取上下文
    CGContextSetLineWidth(ctx, _progressWidth); //设置线条宽度

    CGPoint center = CGPointMake(rect.size.width / 2, rect.size.height / 2);  //设置圆心位置
    CGFloat radius = (rect.size.width - 2 * _progressWidth) * 0.5;  //设置半径
    CGFloat startA = - M_PI_2;  //圆起点位置
    CGFloat endA = -M_PI_2 + M_PI * 2 * _progress;  //圆终点位置
    
    UIBezierPath *bgCirclePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:2*M_PI clockwise:YES];
    [[UIColor lightGrayColor] setStroke];//设置描边颜色
    CGContextAddPath(ctx, bgCirclePath.CGPath);//把路径添加到上下文
    CGContextStrokePath(ctx);//渲染

    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
    [UIColorHex(#f3b132) setStroke];
    CGContextAddPath(ctx, path.CGPath);
    CGContextStrokePath(ctx);
}

在改变进度时,请求重新绘制:

-(void)setProgress:(float)progress
{
    _progress = progress;
    [self setNeedsDisplay];
}
七、长度动画

业余接的一个美术学院学生的iPad项目(iPad搜索“傣纸的故事”),需要动态展示一些物件的大小尺寸,也不用麻烦设计,直接Quartz2D+Core Animation搞掂。最终效果如下图:
在这里插入图片描述
核心代码:

1.画出完整的虚线
- (void)drawRect:(CGRect)rect {
    //获得处理的上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    //线条宽
    CGContextSetLineWidth(context, 2.0);
    //线条颜色
    CGContextSetStrokeColorWithColor(context, ColorForDardTheme.CGColor);
    //画虚线
    CGFloat dashArray[] = {3, 1};//表示先画3个实点再画1个虚点,即实点多虚点少表示虚线点大且间隔小,实点少虚点多表示虚线点小且间隔大
    CGContextSetLineDash(context, 1, dashArray, 1);//最后的参数1代表排列的个数
    //起点坐标
    CGContextMoveToPoint(context, 0, rect.size.height/2);
    //终点坐标
    CGContextAddLineToPoint(context, rect.size.width, rect.size.height/2);
    //绘制路径
    CGContextStrokePath(context);

}

2.加一个遮罩动画就动起来啦
-(void)showAnimation:(HYPointLineDirect)direct{
    CGFloat originFrameX,endPositionX;
    switch (direct) {
        case HYPointLineDirectLeft:
            originFrameX = self.bounds.size.width;
            endPositionX = self.bounds.size.width/2;
            break;
        case HYPointLineDirectRight:
            originFrameX = -self.bounds.size.width;
            endPositionX = self.bounds.size.width/2;
            break;
        default:
            originFrameX = self.bounds.size.width;
            endPositionX = self.bounds.size.width/2;
            break;
    }

    UIView *maskView = [[UIView alloc] initWithFrame:CGRectMake(originFrameX, 0, self.frame.size.width, self.frame.size.height)];
        maskView.backgroundColor =  [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0];
    [self setMaskView:maskView];
    
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.x"];
    animation.toValue = @(endPositionX);
    animation.duration = 1.0;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeBoth;
    [maskView.layer addAnimation:animation forKey:nil];
}

暂时就记得这几个例子。后面有再更新,
总结就是三步:
1.新建类继承UIView
2.重写drawRect:方法,在方法内画画
3.在需要刷新时调用setNeedsDisplay进行重绘

可怜的我辛苦敲代码之余还抽空写博客✍️,兄弟底部点个赞鼓励下再走嘛🥺~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值