引入了Core Graphices框架功能,演示如何画线条,文本,改变线条的额粗细,颜色,以及保存和恢复图形上下文。

要在一个视图中进行自定义绘制,我们必须首先获得当前图形上下文。图形上下文(CGContext)是一个绘图画布,它存放绘图信息,如颜色,线条宽度和字体。在调用drawRect:之前,由UIView配置当前图形上下文。UIGraphicsGetCurrentContext函数返回已经为当前UIView所配置的图形上下文。

//获取当前图形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    //保存这个上下文,因为我们需要上下翻转它
    CGContextSaveGState(context);
//获取当前图形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    //保存这个上下文,因为我们需要上下翻转它
    CGContextSaveGState(context);
/*通过调用CGContextRef中的CGContextTranslateCTM函数把坐标原点转换到左下角,该函数有两个参数,即水平和垂直方
/*通过调用CGContextRef中的CGContextTranslateCTM函数把坐标原点转换到左下角,该函数有两个参数,即水平和垂直方
向的变换数值。然后使用CGContextScaleCTM函数颠倒y轴,该函数有两个参数,即x轴和y轴的变换比例,第一个参数为1,保
向的变换数值。然后使用CGContextScaleCTM函数颠倒y轴,该函数有两个参数,即x轴和y轴的变换比例,第一个参数为1,保
持x轴不变,而第二个参数为-1,表示颠倒y轴*/
持x轴不变,而第二个参数为-1,表示颠倒y轴*/
//向下移动该上下文坐标原点
    CGContextTranslateCTM(context, 0, self.view.bounds.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);      //向上翻转图像上下文
    
    //以剩余时间来创建一个字符串
    NSString  *str = [NSString stringWithFormat:@"Time remaining:%i seconds", timeLeft];
    
    //选择字体为16pt Helvetica
    CGContextSelectFont(context, "Helvetica", 16, kCGEncodingMacRoman);
    CGContextSetTextDrawingMode(context, kCGTextFill);      //设置绘制模式
    
    //设置文本颜色为黑色
    CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
    
    //转换str为一个C 字符串并显示它
    CGContextShowTextAtPoint(context, 10.0, 10.0, [str cStringUsingEncoding:[NSString defaultCStringEncoding]], str.length);
    CGContextRestoreGState(context);    //恢复上下文
    
    //如果炮弹在屏幕上
    if (cannonballOnScreen) 
    {
        //创建矩形并在其中绘制炮弹
        CGRect cannonballRect = CGRectMake(cannonball.x, cannonball.y, CANNON_BASE_RADIUS * 2, CANNON_BASE_RADIUS * 2);
        UIImage *image = [UIImage imageNamed:@"cannonball80.png"];
        
        //绘制图片到矩形中
        CGContextDrawImage(context, cannonballRect, image.CGImage);
    }
    
    //绘制加农炮炮管
    //移动加农炮底座到视图中间的位置
    CGContextMoveToPoint(context, 0 , self.view.frame.size.height / 2);
    
    //添加一根到加农炮炮管终端的线条
    CGContextAddLineToPoint(context, barrelEnd.x , barrelEnd.y);
    CGContextSetLineWidth(context, 20);             //设置线条粗细
    CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);        //黑色
    CGContextStrokePath(context);       //绘制线条
    
    //为加农炮底座创建矩形
    CGRect cannonBase = CGRectMake(0, self.view.frame.size.height / 2 - CANNON_BASE_RADIUS, CANNON_BASE_RADIUS, CANNON_BASE_RADIUS * 2);
    
    //加载加农炮底座图片
    UIImage *baseImage = [UIImage imageNamed:@"cannon_base.png"];
    
    //把加农炮底座图片绘制到矩形中
    CGContextDrawImage(context, cannonBase, baseImage.CGImage);
    
    //在拦截器两个端点之间添加一根线
    CGContextMoveToPoint(context, blocker.start.x, blocker.start.y);
    CGContextAddLineToPoint(context, blocker.end.x, blocker.end.y);
    CGContextSetLineWidth(context, LINE_WIDTH);
    
    CGContextStrokePath(context);       //绘制线条
    
    //计算目标每个分段的长度
    float pieceLength = (TARGET_END - TARGET_BEGINING) / TARGET_PIECES;
    
    //移到目标起点
    CGContextMoveToPoint(context, target.start.x, target.start.y);
    
    //绘制每个目标分段
    for (int i = 1; i <= TARGET_PIECES; i++)
    {
        //相邻分段以黄、蓝色区分开
        if(i % 2 == 0)
        {
            CGContextSetRGBStrokeColor(context, 1, 1, 0, 1);
        }
        else 
        {
            CGContextSetRGBStrokeColor(context, 0, 0, 0.5, 1);
        }
        
        //移到下一个分段的端点
        CGContextMoveToPoint(context, target.end.x, target.start.y + pieceLength * (i - 1));
        
        //如果这个分段还没有被击中
        if(!targetPieceHit[i - 1])
        {
            //为该分段添加一条线
            CGContextAddLineToPoint(context, target.end.x, target.start.y + pieceLength * i);
            CGContextStrokePath(context);      //绘制分段
        }
    }
//向下移动该上下文坐标原点
    CGContextTranslateCTM(context, 0, self.view.bounds.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);      //向上翻转图像上下文
    
    //以剩余时间来创建一个字符串
    NSString  *str = [NSString stringWithFormat:@"Time remaining:%i seconds", timeLeft];
    
    //选择字体为16pt Helvetica
    CGContextSelectFont(context, "Helvetica", 16, kCGEncodingMacRoman);
    CGContextSetTextDrawingMode(context, kCGTextFill);      //设置绘制模式
    
    //设置文本颜色为黑色
    CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
    
    //转换str为一个C 字符串并显示它
    CGContextShowTextAtPoint(context, 10.0, 10.0, [str cStringUsingEncoding:[NSString defaultCStringEncoding]], str.length);
    CGContextRestoreGState(context);    //恢复上下文
    
    //如果炮弹在屏幕上
    if (cannonballOnScreen) 
    {
        //创建矩形并在其中绘制炮弹
        CGRect cannonballRect = CGRectMake(cannonball.x, cannonball.y, CANNON_BASE_RADIUS * 2, CANNON_BASE_RADIUS * 2);
        UIImage *image = [UIImage imageNamed:@"cannonball80.png"];
        
        //绘制图片到矩形中
        CGContextDrawImage(context, cannonballRect, image.CGImage);
    }
    
    //绘制加农炮炮管
    //移动加农炮底座到视图中间的位置
    CGContextMoveToPoint(context, 0 , self.view.frame.size.height / 2);
    
    //添加一根到加农炮炮管终端的线条
    CGContextAddLineToPoint(context, barrelEnd.x , barrelEnd.y);
    CGContextSetLineWidth(context, 20);             //设置线条粗细
    CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);        //黑色
    CGContextStrokePath(context);       //绘制线条
    
    //为加农炮底座创建矩形
    CGRect cannonBase = CGRectMake(0, self.view.frame.size.height / 2 - CANNON_BASE_RADIUS, CANNON_BASE_RADIUS, CANNON_BASE_RADIUS * 2);
    
    //加载加农炮底座图片
    UIImage *baseImage = [UIImage imageNamed:@"cannon_base.png"];
    
    //把加农炮底座图片绘制到矩形中
    CGContextDrawImage(context, cannonBase, baseImage.CGImage);
    
    //在拦截器两个端点之间添加一根线
    CGContextMoveToPoint(context, blocker.start.x, blocker.start.y);
    CGContextAddLineToPoint(context, blocker.end.x, blocker.end.y);
    CGContextSetLineWidth(context, LINE_WIDTH);
    
    CGContextStrokePath(context);       //绘制线条
    
    //计算目标每个分段的长度
    float pieceLength = (TARGET_END - TARGET_BEGINING) / TARGET_PIECES;
    
    //移到目标起点
    CGContextMoveToPoint(context, target.start.x, target.start.y);
    
    //绘制每个目标分段
    for (int i = 1; i <= TARGET_PIECES; i++)
    {
        //相邻分段以黄、蓝色区分开
        if(i % 2 == 0)
        {
            CGContextSetRGBStrokeColor(context, 1, 1, 0, 1);
        }
        else 
        {
            CGContextSetRGBStrokeColor(context, 0, 0, 0.5, 1);
        }
        
        //移到下一个分段的端点
        CGContextMoveToPoint(context, target.end.x, target.start.y + pieceLength * (i - 1));
        
        //如果这个分段还没有被击中
        if(!targetPieceHit[i - 1])
        {
            //为该分段添加一条线
            CGContextAddLineToPoint(context, target.end.x, target.start.y + pieceLength * i);
            CGContextStrokePath(context);      //绘制分段
        }
    }