每日更新关注:http://weibo.com/hanjunqiang 
新浪微博

第一步:先科普一下基础知识:

Core Graphics是基于C的API,可以用于一切绘图操作

Core Graphics 和Quartz 2D的区别

quartz是一个通用的术语,用于描述在IOS和MAC OS X ZHONG 整个媒体层用到的多种技术 包括图形、动画、音频、适配。

Quart 2D 是一组二位绘图和渲染API,Core Graphic会使用到这组API

Quartz Core 专指Core Animation用到的动画相关的库、API和类

点和像素的对比

系统拥有坐标系,如320*480 硬件有retain屏幕和非retain屏:如320*480、640*960

Core Graphics 使用的是系统的坐标系来绘制图片。在分辨率为640*960手机上绘制图片时,实际上Core Graphics 的坐标是320*480。这个时候每个坐标系上的点,实际上拥有两个像素。

图形上下文

Core Graphics 使用图形上下文进行工作,这个上下文的作用像画家的画布一样。

在图形上下文之外是无法绘图的,我们可以自己创建一个上下文,但是性能和内存的使用上,效率是非常低得。

我们可以通过派生一个UIView的子类,获得它的上下文。在UIView中调用drawRect:方法时,会自动准备好一个图形上下文,可以通过调用

UIGraphicsGetCurrentContext()来获取。 因为它是运行期间绘制图片,我们可以动态的做一些额外的操作

Core Graphics的优点

快速、高效,减小应用的文件大小。同时可以自由地使用动态的、高质量的图形图像。 使用Core Graphics,可以创建直线、路径、渐变、文字与图像等内容,并可以做变形处理。

绘制自定义视图

drawRect:是系统的方法,不要从代码里面直接调用 drawRect:,而应该使用setNeedsDisplay重绘.

需要知道的术语

  • 路径 path
  • 阴影 shadow
  • 笔画 stroke
  • 剪裁路径 Clip Path
  • 线条粗细 Line Width
  • 混合模式 Blend Mode
  • 填充色 Fill Color
  • 当前形变矩阵 Current Transform Matrix
  • 线条图案 Line Dash

图形上下文

一个图形上下文好比是画布上的一副扁平的图画 执行绘画动作,这些动作是在同一个图层上完成的。 图形上下文不允许将内容分不到多个图层中,如果有需求在不同图层上画,可以考虑使用视图层次结构,创建多个UIView,并将他们作为父视图的子视图

图形上下文栈可以把图形上下文的当前状态保存下来,并在执行一些动作后再次恢复回来

CGContextSaveGState();

CGContextStoreGState();

路径、渐变、文字和图像

1. 使用UIBezierPath创建路径

2. 手动创建路径 moveToPoint addLineToPoint addArcWithCenter addCurveToPoint

渐变,渐变可以在指定方向上,以可变的比率在一系列颜色之间转化

线性渐变:沿着一条定义好了起点和重点的直线方向,呈线性变化。如果这条线有一定角度,线性渐变也会沿相同路径变化

放射渐变:颜色顺着两个原型之间的方向线性变化,这两个园为起始圆和终止圆,每隔圆都有自己的圆心和班级

文字

darwAtPoint

drawInRect

图像

Core Graphics 不会保持图像的长宽比例,Core Graphics会将图像的边界设置为CGrect,不管图片是否变形 darwAtPoint drawInRect

第二步:代码部分:

基础画法就不多讲啦!都通用:

第一种绘图形式:在UIView的子类方法drawRect:中绘制一个蓝色圆,使用UIKit在Cocoa为我们提供的当前上下文中完成绘图任务。
 
    - (void) drawRect: (CGRect) rect { 

    UIBezierPath* p = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; 

    [[UIColor blueColor] setFill]; 

    [p fill]; 

    } 

 
第二种绘图形式:使用Core Graphics实现绘制蓝色圆。
 
    - (void) drawRect: (CGRect) rect { 

    CGContextRef con = UIGraphicsGetCurrentContext(); 

    CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); 

    CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); 

    CGContextFillPath(con); 

    } 

 
第三种绘图形式:我将在UIView子类的drawLayer:inContext:方法中实现绘图任务。drawLayer:inContext:方法是一个绘制图层内容的代理方法。为了能够调用drawLayer:inContext:方法,我们需要设定图层的代理对象。但要注意,不应该将UIView对象设置为显示层的委托对象,这是因为UIView对象已经是隐式层的代理对象,再将它设置为另一个层的委托对象就会出问题。轻量级的做法是:编写负责绘图形的代理类。在MyView.h文件中声明如下代码:
 
    @interface MyLayerDelegate : NSObject 

    @end 

 
然后MyView.m文件中实现接口代码:
 
    @implementation MyLayerDelegate 

    - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx { 

      UIGraphicsPushContext(ctx); 

      UIBezierPath* p = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; 

      [[UIColor blueColor] setFill]; 

      [p fill]; 

      UIGraphicsPopContext(); 

    } 

    @end 

 
直接将代理类的实现代码放在MyView.m文件的#import代码的下面,这样感觉好像在使用私有类完成绘图任务(虽然这不是私有类)。需要注意的是,我们所引用的上下文并不是当前上下文,所以为了能够使用UIKit,我们需要将引用的上下文转变成当前上下文。
 
因为图层的代理是assign内存管理策略,那么这里就不能以局部变量的形式创建MyLayerDelegate实例对象赋值给图层代理。这里选择在MyView.m中增加一个实例变量,因为实例变量默认是strong:
 
    @interface MyView () { 

    MyLayerDelegate* _layerDeleagete; 

    } 

    @end 

 
使用该图层代理:
 
    MyView *myView = [[MyView alloc] initWithFrame: CGRectMake(0, 0, 320, 480)]; 

    CALayer *myLayer = [CALayer layer]; 

    _layerDelegate = [[MyLayerDelegate alloc] init]; 

    myLayer.delegate = _layerDelegate; 

    [myView.layer addSublayer:myLayer]; 

    [myView setNeedsDisplay]; // 调用此方法,drawLayer: inContext:方法才会被调用。 

 
第四种绘图形式: 使用Core Graphics在drawLayer:inContext:方法中实现同样操作,代码如下:
 
    - (void)drawLayer:(CALayer*)lay inContext:(CGContextRef)con { 

    CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); 

    CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); 

    CGContextFillPath(con); 

    } 

 
最后,演示UIGraphicsBeginImageContextWithOptions的用法,并从上下文中生成一个UIImage对象。生成UIImage对象的代码并不需要等待某些方法被调用后或在UIView的子类中才能去做。
 
第五种绘图形式: 使用UIKit实现:
 
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0); 

    UIBezierPath* p = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; 

    [[UIColor blueColor] setFill]; 

    [p fill]; 

    UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); 

    UIGraphicsEndImageContext(); 

 
解释一下UIGraphicsBeginImageContextWithOptions函数参数的含义:第一个参数表示所要创建的图片的尺寸;第二个参数用来指定所生成图片的背景是否为不透明,如上我们使用YES而不是NO,则我们得到的图片背景将会是黑色,显然这不是我想要的;第三个参数指定生成图片的缩放因子,这个缩放因子与UIImage的scale属性所指的含义是一致的。传入0则表示让图片的缩放因子根据屏幕的分辨率而变化,所以我们得到的图片不管是在单分辨率还是视网膜屏上看起来都会很好。
 
第六种绘图形式: 使用Core Graphics实现:
 
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0); 

    CGContextRef con = UIGraphicsGetCurrentContext(); 

    CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); 

    CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); 

    CGContextFillPath(con); 

    UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); 

    UIGraphicsEndImageContext();

第三步:实践部分:

第一种:基本图形绘制

/**
 *  什么调用:当你视图第一次显示的时候就会调用
 *  作用:绘图
 *  @param rect = self.bounds
 */
- (void)drawRect:(CGRect)rect
{
    // 1.获取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // 2.拼接路径
    UIBezierPath *path = [UIBezierPath bezierPath];

    CGPoint startP = CGPointMake(10, 125);
    CGPoint endP = CGPointMake(240, 125);
    CGPoint controlP = CGPointMake(125, 0);
    [path moveToPoint:startP];
    [path addQuadCurveToPoint:endP controlPoint:controlP];

    // 3.把路径添加到上下文
    CGContextAddPath(ctx, path.CGPath);

    // 4.渲染上下文到视图
    CGContextStrokePath(ctx);
}

- (void)drawLine
{
    // 1.获取上下文
    // CGContextRef CG CoreGraphics Ref 引用
    // 目前学的上下文都跟UIGraphics有关,以后想直接获取上下文,直接敲一个UIGraphics
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // 2.设置绘图信息(拼接路径)
    UIBezierPath *path = [UIBezierPath bezierPath];

    // 设置起点
    [path moveToPoint:CGPointMake(10, 10)];

    // 添加一条线到某个点
    [path addLineToPoint:CGPointMake(125, 125)];
    [path addLineToPoint:CGPointMake(240, 10)];
    // 3.把路径添加到上下文
    // 直接把UIKit的路径转换成CoreGraphics,CG开头就能转
    CGContextAddPath(ctx, path.CGPath);

    // 4.把上下文渲染到视图
    // Stroke描边
    CGContextStrokePath(ctx);
}

- (void)draw2Line
{
    // 1.获取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // 2.拼接路径
    UIBezierPath *path = [UIBezierPath bezierPath];

    // 设置起点
    [path moveToPoint:CGPointMake(10, 125)];

    // 添加一条线到某个点
    [path addLineToPoint:CGPointMake(230, 125)];

    //    // 设置起点
    //    [path moveToPoint:CGPointMake(10, 10)];
    //
    //    // 添加一条线到某个点
    //    [path addLineToPoint:CGPointMake(125, 100)];

    UIBezierPath *path1 = [UIBezierPath bezierPath];

    [path1 moveToPoint:CGPointMake(10, 10)];

    [path1 addLineToPoint:CGPointMake(125, 100)];

    // 3.把路径添加到上下文
    CGContextAddPath(ctx, path.CGPath);
    CGContextAddPath(ctx, path1.CGPath);

    // 设置绘图状态
    // 设置线宽
    CGContextSetLineWidth(ctx, 10);
    CGContextSetLineCap(ctx, kCGLineCapRound);
    //    CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1);
    [[UIColor redColor] set];

    // 4.渲染上下文到视图
    CGContextStrokePath(ctx);

}

每日更新关注:http://weibo.com/hanjunqiang 
新浪微博

第二种:下载进度条:

- (void)setProgress:(CGFloat)progress
{
    _progress = progress;
    self.myLabel.text = [NSString stringWithFormat:@"%.2f%%",progress*100];
    //    [self drawRect:self.bounds];
    // 重新绘制
    // 在view上做一个重绘的标记,当下次屏幕刷新的时候,就会调用drawRect.
    [self setNeedsDisplay];
}

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.

 // 当视图显示的时候会调用 默认只会调用一次
- (void)drawRect:(CGRect)rect
{
     // 1.获取上下文
     CGContextRef ctx = UIGraphicsGetCurrentContext();

     // 2.拼接路径
     CGPoint center = CGPointMake(50, 50);
     CGFloat radius = 50 - 2;
     CGFloat startA = -M_PI_2;
     CGFloat endA = -M_PI_2 + _progress * M_PI * 2;
     UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];

     // 3.把路径添加到上下文
     CGContextAddPath(ctx, path.CGPath);

     // 4.把上下文渲染到视图
     CGContextStrokePath(ctx);

}

每日更新关注:http://weibo.com/hanjunqiang 
新浪微博

第三种:饼图

- (void)drawRect:(CGRect)rect
{
    // Drawing code

    NSArray *data = @[@25,@25,@50];

    // 1.获取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // 2.拼接路径
    CGPoint center = CGPointMake(125, 125);
    CGFloat radius = 120;
    CGFloat startA = 0;
    CGFloat angle = 0;
    CGFloat endA = 0;

    for (NSNumber *number in data) {
        // 2.拼接路径
        startA = endA;
        angle = number.intValue / 100.0 * M_PI * 2;
        endA = startA + angle;
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
        [path addLineToPoint:center];

        [[UIColor randomColor] set];
        // 把路径添加上下文
        CGContextAddPath(ctx, path.CGPath);

        // 渲染
        CGContextFillPath(ctx);

    }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGFloat a = arc4random_uniform(6);
    //CGFloat a =  arc4random()%6;
    NSLog(@"随机数--%f",a);

    [self setNeedsDisplay];
}

- (void)drawPie
{
    // 1.获取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // 2.拼接路径
    CGPoint center = CGPointMake(125, 125);
    CGFloat radius = 120;
    CGFloat startA = 0;
    CGFloat angle = 0;
    CGFloat endA = 0;

    // 第一个扇形
    angle = 25 / 100.0 * M_PI * 2;
    endA = startA + angle;
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
    [path addLineToPoint:center];
    // 添加到上下文
    CGContextAddPath(ctx, path.CGPath);
    [[UIColor redColor] set];

    // 渲染
    CGContextFillPath(ctx);

    // 第二个扇形
    startA = endA;
    angle = 25 / 100.0 * M_PI * 2;
    endA = startA + angle;
    UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
    [path1 addLineToPoint:center];
    // 添加到上下文
    CGContextAddPath(ctx, path1.CGPath);
    [[UIColor greenColor] set];
    // 渲染
    CGContextFillPath(ctx);

    // 第三个扇形
    startA = endA;
    angle = 50 / 100.0 * M_PI * 2;
    endA = startA + angle;
    UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
    [path2 addLineToPoint:center];
    // 添加到上下文
    CGContextAddPath(ctx, path2.CGPath);
    [[UIColor blueColor] set];
    // 渲染
    CGContextFillPath(ctx);

}



每日更新关注:http://weibo.com/hanjunqiang 
新浪微博

第四种:柱形图

- (void)drawRect:(CGRect)rect
{
     NSArray *data = @[@25,@25,@50];
     NSInteger count = data.count;

     CGFloat w = rect.size.width / (2 * count - 1);
     CGFloat h = 0;
     CGFloat x = 0;
     CGFloat y = 0;
     CGFloat viewH = rect.size.height;
     // 1.获取上下文
     CGContextRef ctx = UIGraphicsGetCurrentContext();

     for (int i = 0; i < count; i++) {
     h = viewH * [data[i] intValue] / 100.0;
     x = 2 * w * i;
     y = viewH - h;
     // 2.拼接路径
     UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(x, y, w, h)];

     // 3.添加路径到上下文
     CGContextAddPath(ctx, path.CGPath);

     [[UIColor randomColor] set];

     // 4.渲染
     CGContextFillPath(ctx);
     }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
     [self setNeedsDisplay];
}



每日更新关注:http://weibo.com/hanjunqiang 
新浪微博

第五种:模仿UIImageView

- (void)setImage:(UIImage *)image
 {
     _image = image;
     [self setNeedsDisplay];
}

 // Only override drawRect: if you perform custom drawing.
 // An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
 // Drawing code

     [_image drawInRect:rect];
}





每日更新关注:http://weibo.com/hanjunqiang 
新浪微博

第六种:图形上下文线

- (void)drawRect:(CGRect)rect
{
    // Drawing code

    // 1.获取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // 把ctx拷贝一份放在栈中
    CGContextSaveGState(ctx);

    // 2.拼接路径(绘图的信息)
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(10, 125)];
    [path addLineToPoint:CGPointMake(240, 125)];

    // 3.路径添加到上下文
    CGContextAddPath(ctx, path.CGPath);

    // 设置绘图的状态
    [[UIColor redColor] set];
    CGContextSetLineWidth(ctx, 10);
    CGContextSetLineCap(ctx, kCGLineCapRound);

    // 4.渲染
    CGContextStrokePath(ctx);

    // 第二根线
    UIBezierPath *path1 = [UIBezierPath bezierPath];
    [path1 moveToPoint:CGPointMake(125, 10)];
    [path1 addLineToPoint:CGPointMake(125, 240)];
    CGContextAddPath(ctx, path1.CGPath);

    // 把栈顶上下文取出来,替换当前上下文
    CGContextRestoreGState(ctx);

    // 设置绘图的状态
    //    [[UIColor blackColor] set];
    //    CGContextSetLineWidth(ctx, 1);
    //    CGContextSetLineCap(ctx, kCGLineCapButt);

    // 4.渲染
    CGContextStrokePath(ctx);

}



每日更新关注:http://weibo.com/hanjunqiang 
新浪微博

第七种:矩形操作

- (void)drawRect:(CGRect)rect
{
    // Drawing code

    // 1.获取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // 注意:你的路径一定放在上下文矩阵操作之后
    // 平移上下文
    CGContextTranslateCTM(ctx, 50, 100);

    // 旋转上下文
    CGContextRotateCTM(ctx, M_PI_4);

    // 缩放上下文
    CGContextScaleCTM(ctx, 0.5, 1.2);

    // 2.拼接路径
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-50, -100, 150, 200)];

    // 3.把路径添加到上下文
    CGContextAddPath(ctx, path.CGPath);

    [[UIColor redColor] set];

    // 4.渲染
    CGContextFillPath(ctx);

}



每日更新关注:http://weibo.com/hanjunqiang 
新浪微博

iOS开发者交流QQ群: 446310206  欢迎加入(demo在这里)!

iOS中 CoreGraphics快速绘图(详解) 韩俊强的博客的更多相关文章

  1. iOS中 扫描二维码/生成二维码详解 韩俊强的博客

    最近大家总是问我有没有关于二维码的demo,为了满足大家的需求,特此研究了一番,希望能帮到大家! 每日更新关注:http://weibo.com/hanjunqiang  新浪微博 指示根视图: se ...

  2. iOS中 HTTP/Socket/TCP/IP通信协议详解 韩俊强的博客

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博 简单介绍: // OSI(开放式系统互联), 由ISO(国际化标准组织)制定 // 1. 应用层 // 2. 表示层 ...

  3. iOS中 本地通知/本地通知详解 韩俊强的博客

    布局如下:(重点讲本地通知) iOS开发者交流QQ群: 446310206 每日更新关注:http://weibo.com/hanjunqiang  新浪微博 Notification是智能手机应用编 ...

  4. iOS中 Realm的学习与使用 韩俊强的博客

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博! 有问题或技术交流可以咨询!欢迎加入! 这篇直接搬了一份官方文档过来看的 由于之前没用markdown搞的乱七八糟的 ...

  5. iOS中 最新微信支付/最全的微信支付教程详解 韩俊强的博客

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博! 亲们, 首先让我们来看一下微信支付的流程吧. 1. 注册微信开放平台,创建应用获取appid,appSecret, ...

  6. iOS中 语音识别功能/语音转文字教程详解 韩俊强的博客

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博 原文地址:http://blog.csdn.net/qq_31810357/article/details/5111 ...

  7. iOS中 蓝牙2.0详解/ios蓝牙设备详解 韩俊强的博客

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博 整体布局如下:     程序结构如右图: 每日更新关注:http://weibo.com/hanjunqiang  ...

  8. iOS中 断点下载详解 韩俊强的博客

    布局如下: 基本拖拉属性: #import "ViewController.h" #import "AFNetworking.h" @interface Vie ...

  9. iOS中 自定义cell分割线/分割线偏移 韩俊强的博客

    在项目开发中我们会常常遇到tableView 的cell分割线显示不全,左边会空出一截像素,更有甚者想改变系统的分割线,并且只要上下分割线的一个等等需求,今天重点解决以上需求,仅供参考: 每日更新关注 ...

随机推荐

  1. hdu 1166 线段树(sum+单点修改)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  2. kafka快速入门

    一.kafka简介 kafka,ActiveMQ,RabbitMQ是当今最流行的分布式消息中间件,其中kafka在性能及吞吐量方面是三者中的佼佼者,不过最近查阅官网时,官方与它的定义为一个分布式流媒体 ...

  3. vue loadMore 上拉刷新不能实现的坑

    1.如果你写的代码没问题,但依然不能实现上拉刷新效果,那你有可能是缺少了overflow: scroll 2.如果上拉刷新一直在加载状态,需要调用this.$refs.loadmore.onBotto ...

  4. 修改SQL数据库中表字段类型时,报“一个或多个对象访问此列”错误的解决方法

    在SQL数据库中使用SQL语句(格式:alter table [tablename] alter column [colname] [newDataType])修改某表的字段类型时,报一下错误:由于一 ...

  5. 修改firefox的默认缩放比

    我们在使用firefox时,发现页面的缩放比只能一个一个手动调整,当跳转到新的页面时默认缩放比又还原了,这个时候又要重新调整,相当不方便. 下面介绍修改默认缩放比的方法: 首先,打开firefox,然 ...

  6. final、finally与finalize的区别

    1. final  在java中,final可以用来修饰类,方法和变量(成员变量或局部变量).下面将对其详细介绍. 1.1 修饰类 当用final修饰类的时,表明该类不能被其他类所继承.当我们需要让一 ...

  7. Java Native方法

    一. 什么是Native Method   简单地讲,一个Native Method就是一个java调用非java代码的接口.一个Native Method是这样一个java的方法:该方法的实现由非j ...

  8. H5canvas基础

    本篇文章开始讲解HTML5的核心功能之一:Canvas 通过Canvas可以动态生成和展示图形.图表.图像以及动画. Canvas API功能非常多,我们将讨论最常用的功能. 我们先新建一个canva ...

  9. 吴恩达深度学习第4课第3周编程作业 + PIL + Python3 + Anaconda环境 + Ubuntu + 导入PIL报错的解决

    问题描述: 做吴恩达深度学习第4课第3周编程作业时导入PIL包报错. 我的环境: 已经安装了Tensorflow GPU 版本 Python3 Anaconda 解决办法: 安装pillow模块,而不 ...

  10. C#利用Attribute实现简易AOP介绍

    首先看一段简单的代码: public partial class Form1 : Form { public Form1() { InitializeComponent(); } //来自UI层的调用 ...