Quartz2D使用

先看图

这里写图片描述


这里写图片描述


这里写图片描述


这里写图片描述


代码下载请猛戳这里



使用路径绘制图形

/**
 *  路径的使用
 *
 *  @param x1 起点x
 *  @param y1 起点y
 *  @param x2 终点x
 *  @param y2 终点y
 */
void usedPathDraw(CGFloat selfWidth)
{
    //1.获取图形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);

    //2.创建路径
    CGMutablePathRef path = CGPathCreateMutable();

    //3.拼接路径
    CGPathMoveToPoint(path, NULL, 10, 50);
    CGPathAddLineToPoint(path, NULL, 90, 50);

    //4.添加路径到图形上下文
    CGContextAddPath(context, path);

    //5.渲染
    CGContextStrokePath(context);

    CGMutablePathRef path1 = CGPathCreateMutable();
    CGPathMoveToPoint(path1, NULL, selfWidth/2 - 40, 50);
    CGPathAddLineToPoint(path1, NULL, selfWidth/2 + 40, 50);
    CGFloat lengths[] = {10,5};
    CGContextSetLineDash(context, 0, lengths, 2);
    CGContextAddPath(context, path1);
    CGContextStrokePath(context);

    CGMutablePathRef path2 = CGPathCreateMutable();
    CGPathMoveToPoint(path2, NULL, selfWidth - 90, 50);
    CGPathAddLineToPoint(path2, NULL, selfWidth - 10, 50);
    CGFloat lengths1[] = {7,3,5,4,2,6,1};
    CGContextSetLineDash(context, 0, lengths1, 7);
    CGContextSetLineWidth(context, 5);
    CGContextAddPath(context, path2);
    CGContextStrokePath(context);

    //6.释放路径
    CGPathRelease(path);
    CGContextRestoreGState(context);
}

贝瑟尔路径绘制图形

/**
 *  贝瑟尔路径的使用
 */
- (void)usedBezierPath
{
    CGPoint center = CGPointMake(50, 150);
    //1.创建贝瑟尔路径
    /*
        (CGPoint)center:圆心
        radius:(CGFloat)radius:半径
        startAngle:(CGFloat)startAngle:开始角度
        endAngle:(CGFloat)endAngle:结束角度
        clockwise:(BOOL)clockwise:是否使用ARC技术,不然需要释放路径
     */
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:40 startAngle:0 endAngle:M_PI*1.5 clockwise:YES];
    //2.拼接路径
    [path addLineToPoint:center];
    [path closePath];
    //3.渲染
    [path stroke];

    path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(Self_Width/2 - 40, 110, 80, 80) cornerRadius:10];
    [path stroke];
}

合成图片

/**
 *  合成图片
 *
 *  @param basicImage 背景图
 *  @param otherImage 前景图
 *  @param size       合成的图像大小
 *
 *  @return 合成后的图像
 */
- (UIImage *)imageSynthesis:(UIImage *)basicImage andOther:(UIImage *)otherImage andSize:(CGSize)size
{
    //1.创建一个基于位图的图形上下文(开启一个基于位图的上下文)
    /*
        CGSize size:位图尺寸,
        BOOL opaque:位图透明度,
        CGFloat scale:适用于位图的比例因子。如果你指定一个值为0.0时,比例因子设置为设备的主屏幕的比例因子。

        说明:1.上小文 : 基于位图(bitmap) ,  所有的东西需要绘制到一张新的图片上去
             2.这行代码过后.就相当于常见一张新的bitmap,也就是新的UIImage对象
     */
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);

    //2.绘制背景
    [basicImage drawInRect:CGRectMake(0, 0, size.width, size.height)];

    //3.绘制前景
    CGFloat spacingProportion = 0.08;
    CGFloat fProportion = 0.1;
    CGFloat fWidth = size.width*fProportion;
    CGFloat fHeight = size.height*fProportion;
    [otherImage drawInRect:CGRectMake(size.width*(1 - spacingProportion) - fWidth, size.height*(1 - spacingProportion) - fHeight, fWidth, fHeight)];

    // 4.从上下文中取得制作完毕的UIImage对象
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    // 5.结束上下文
    UIGraphicsEndImageContext();

    return image;
}

裁剪图像

/**
 *  裁剪图像
 *
 *  @param image 原图像
 *
 *  @return 裁剪后的图像
 */
- (UIImage *)cutImage:(UIImage *)image
{
    //1.开启一个基于位图的图形上下文
    UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
    //2.创建裁剪路径
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, image.size.width, image.size.height) cornerRadius:10];
    //3.裁剪
    [path addClip];
    //4.画图
    [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
    //5.取图
    UIImage *endImage = UIGraphicsGetImageFromCurrentImageContext();
    //6.结束上下文
    UIGraphicsEndImageContext();

    return endImage;
}

截屏

/**
 *  截屏
 *
 *  @param view 需要截屏的view
 *
 *  @return 截屏后生成的图片
 */
- (UIImage *)screenshots:(UIView *)view
{
    if (view == nil) return nil;

    //1.开启一个基于位图的图形上下文
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0.0);
    //2.渲染到图形上下文
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    //3.结束上下文
    UIGraphicsEndImageContext();
    return image;
}

平铺图像

/**
 *  平铺图像
 */
- (void)backgroundTile
{
    //平铺图高
    CGFloat rowW = Self_Width/3 + 0.1;
    //平铺图宽
    CGFloat rowH = 100;
    //1.开启一个基于位图的图形上下文
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(rowW, rowH), NO, 0.0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    //2.绘制背景
    CGContextAddRect(context, CGRectMake(0, 0, Self_Width, rowH));
    [[UIColor whiteColor] setFill];
    CGContextFillPath(context);
    //3.绘制线
    CGFloat lineH = 1;
    CGContextMoveToPoint(context, 0, rowH - lineH);
    CGContextAddLineToPoint(context, rowW - lineH, rowH - lineH);
    CGContextAddLineToPoint(context, rowW - lineH, 0);
    //4.渲染到图形上下文
    CGContextStrokePath(context);

    //5.获取图像
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    //6.平铺图像
    self.backgroundColor = [UIColor colorWithPatternImage:image];
}

绘制扑克牌

#import "PlayingCardView.h"

@interface PlayingCardView()
{
    //计数绘制了多少张牌
    NSInteger count;
}
/**
 *  牌的中心内容与整个牌面的比例
 */
@property (nonatomic,assign)CGFloat faceCardScaleFactor;

@end

@implementation PlayingCardView
@synthesize faceCardScaleFactor = _faceCardScaleFactor;
#pragma mark - Properties
- (void)setRank:(NSInteger)rank
{
    if (_rank != rank) {
        _rank = rank;
        //重绘牌面
        [self setNeedsDisplay];
    }
}
- (void)setSuit:(NSString *)suit
{
    if (_suit != suit) {
        _suit = suit;
        //重绘牌面
        [self setNeedsDisplay];
    }
}
- (void)setFaceUp:(BOOL)faceUp
{
    if (_faceUp != faceUp) {
        _faceUp = faceUp;
        //重绘牌面
        [self setNeedsDisplay];
    }
}
- (void)setFaceCardScaleFactor:(CGFloat)faceCardScaleFactor
{
    if (_faceCardScaleFactor != faceCardScaleFactor) {
        _faceCardScaleFactor = faceCardScaleFactor;
        //重绘牌面
        [self setNeedsDisplay];
    }
}
/**
 *  牌的中心内容与整个牌面的比例
 */
#define DEFAULR_FACE_CARD_SCALE_FACTOR     0.90
- (CGFloat)faceCardScaleFactor
{
    if (!_faceCardScaleFactor) {
        _faceCardScaleFactor = DEFAULR_FACE_CARD_SCALE_FACTOR;
    }

    return _faceCardScaleFactor;
}

- (void)pinch:(UIPinchGestureRecognizer *)gesture
{
    if (gesture.state == UIGestureRecognizerStateChanged || gesture.state == UIGestureRecognizerStateEnded) {
        //改变牌的中心内容与整个牌面的比例
        self.faceCardScaleFactor *= gesture.scale;
        gesture.scale = 1;
    }
}

#pragma mark - Drawing

//真实的牌高
#define CORNER_FCNT_STANDRAD_HEIGHT      180.0
//真实的牌圆角
#define CORNER_RADIUS                    12.0

/**
 *  绘制的牌和真实的牌之间的比例
 *
 *  @return 比例值
 */
- (float)cornerScaleFactor {return self.bounds.size.height/CORNER_FCNT_STANDRAD_HEIGHT;}
/**
 *  绘制的牌的圆角半径
 *
 *  @return 半径
 */
- (float)cornerRadius {return CORNER_RADIUS*[self cornerScaleFactor];}
/**
 *  绘制的牌的两个角落位置文字在牌面的偏移量
 *
 *  @return 偏移量
 */
- (float)cornerOffset {return [self cornerRadius]/3.0;}


/*

 setNeedsDisplay会调用自动调用drawRect方法,这样可以拿到  UIGraphicsGetCurrentContext,就可以画画了。

 drawRect在以下情况下会被调用:

 1、如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect调用是在Controller->loadView, Controller->viewDidLoad 两方法之后掉用的.所以不用担心在控制器中,这些View的drawRect就开始画了.这样可以在控制器中设置一些值给View(如果这些View draw的时候需要用到某些变量值).

 2、该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。

 3、通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。

 4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。

 以上1,2推荐;而3,4不提倡


 drawRect方法使用注意点:

 1、若使用UIView绘图,只能在drawRect:方法中获取相应的contextRef并绘图。如果在其他方法中获取将获取到一个invalidate的ref并且不能用于画图。drawRect:方法不能手动显示调用,必须通过调用setNeedsDisplay 或者 setNeedsDisplayInRect,让系统自动调该方法。

 2、若使用calayer绘图,只能在drawInContext: 中(类似于drawRect)绘制,或者在delegate中的相应方法绘制。同样也是调用setNeedDisplay等间接调用以上方法

 3、若要实时画图,不能使用gestureRecognizer,只能使用touchbegan等方法来掉用setNeedsDisplay实时刷新屏幕

 */
- (void)drawRect:(CGRect)rect {
    //创建圆角矩形路径
    UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:[self cornerRadius]];

    //裁剪
    [roundedRect addClip];

    //填充颜色
    [[UIColor whiteColor] setFill];
    [roundedRect fill];

    //如果牌面朝上
    if (self.faceUp) {
        if (!count) {
            count = 1;
        }
        NSLog(@"%i",count);
        count++;
        UIImage *faceImage = [UIImage imageNamed:[NSString stringWithFormat:@"%@%@",self.suit,[self rankStrings]]];
        //如果牌面是图像(J,Q,K)
        if (faceImage)
        {
            //通过一个rect缩小一定的大小获得一个新的rect
            CGRect imageRect = CGRectInset(self.bounds,
                                           self.bounds.size.height*(1-self.faceCardScaleFactor),
                                           self.bounds.size.height*(1-self.faceCardScaleFactor));

            //绘制牌面中心图片
            [faceImage drawInRect:imageRect];
        }
        else//牌面不是(J,Q,K)
        {
            //绘制牌面中心内容
            [self drawPips];
        }

        //画牌面的两个角落
        [self drawCorners];
    }
    else//如果牌面朝下
    {
        //绘制牌的背面
        [[UIImage imageNamed:@"cardBack"] drawInRect:self.bounds];
    }

    [[UIColor blackColor] setStroke];
    [roundedRect setLineWidth:5];//设置线宽
    [roundedRect stroke];//边框
}
/**
 *  获取牌面大小字符串
 *
 *  @return 牌面大小字符串
 */
- (NSString *)rankStrings
{
    return @[@"?",@"A",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"J",@"Q",@"K"][self.rank];
}
/**
 *  绘制牌面的角落
 */
- (void)drawCorners
{
    //设置文字段落样式
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.alignment = NSTextAlignmentCenter;//对齐方式

    //设置字体
    UIFont *cornerFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
    cornerFont = [cornerFont fontWithSize:[cornerFont pointSize]*[self cornerScaleFactor]];

    //设置绘制的颜色
    UIColor *cornerColor;
    BOOL isRed = [self.suit isEqualToString:@"♥️"];
    BOOL isRed1 = [self.suit isEqualToString:@"♦️"];
    if (isRed||isRed1)
    {
        cornerColor = [UIColor redColor];
    }
    else
    {
        cornerColor = [UIColor blackColor];
    }

    //创建牌面角落文字的富文本
    NSAttributedString *cornerText = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\n%@",[self rankStrings],self.suit]
                                                                     attributes:@{NSFontAttributeName:cornerFont,
                                                                                  NSParagraphStyleAttributeName:paragraphStyle,
                                                                                  NSForegroundColorAttributeName:cornerColor}];
    CGRect textBounds;
    textBounds.origin = CGPointMake([self cornerOffset], 2*[self cornerOffset]);
    textBounds.size = [cornerText size];
    [cornerText drawInRect:textBounds];

    //获取当前图形上下文句柄
    CGContextRef context = UIGraphicsGetCurrentContext();
    //平行当前上下文的变换矩阵
    CGContextTranslateCTM(context, self.bounds.size.width, self.bounds.size.height);
    //旋转当前上下文的变换矩阵
    CGContextRotateCTM(context, M_PI);
    //渲染文字
    [cornerText drawInRect:textBounds];
}

#pragma mark - Pips
//牌面花色图标的水平间距比例
#define PIP_HOFFSET_PERCENTAGE  0.200
//牌面花色图标的垂直间距比例1(4排,比如9,10)
#define PIP_VOFFSET1_PERCENTAGE 0.090
//牌面花色图标的垂直间距比例2(3排,比如3,6,7,8)
#define PIP_VOFFSET2_PERCENTAGE 0.175
//牌面花色图标的垂直间距比例3(2排,比如4,5)
#define PIP_VOFFSET3_PERCENTAGE 0.270
/**
 *  根据不同的牌绘制牌面中心区域的图案
 */
- (void)drawPips
{
    //牌面最中心有图案的情况
    if (self.rank == 1 || self.rank == 3 || self.rank == 5 || self.rank == 9) {
        [self drawPipsWithHerizontalOffset:0
                            vertiCalOffset:0
                        mirroredVertically:NO];
    }
    //牌面最竖直方向中心两边有图案的情况
    if (self.rank == 6 || self.rank == 7 || self.rank == 8) {
        [self drawPipsWithHerizontalOffset:PIP_HOFFSET_PERCENTAGE
                            vertiCalOffset:0
                        mirroredVertically:NO];
    }
    if (self.rank == 2 || self.rank == 3) {
        [self drawPipsWithHerizontalOffset:0
                            vertiCalOffset:PIP_VOFFSET3_PERCENTAGE
                        mirroredVertically:YES];
    }
    if (self.rank == 7 || self.rank == 8 || self.rank == 10) {
        [self drawPipsWithHerizontalOffset:0
                            vertiCalOffset:PIP_VOFFSET2_PERCENTAGE
                        mirroredVertically:(self.rank != 7)];
    }
    if (self.rank == 4 || self.rank == 5 || self.rank == 6 || self.rank == 7 || self.rank == 8 || self.rank == 9 || self.rank == 10) {
        [self drawPipsWithHerizontalOffset:PIP_HOFFSET_PERCENTAGE
                            vertiCalOffset:PIP_VOFFSET3_PERCENTAGE
                        mirroredVertically:YES];
    }
    if (self.rank == 9 || self.rank == 10) {
        [self drawPipsWithHerizontalOffset:PIP_HOFFSET_PERCENTAGE
                            vertiCalOffset:PIP_VOFFSET1_PERCENTAGE
                        mirroredVertically:YES];
    }
}

//字体大小与牌宽的比例
#define PIP_FONT_SCALE_FACTOR    0.012
/**
 *  牌面中心区域的图案具体绘制
 *
 *  @param hoffSet    水平图案间距
 *  @param voffSet    垂直图案间距
 *  @param upsideDown 是否需要中心对称图形上下文
 */
- (void)drawPipsWithHerizontalOffset:(CGFloat)hoffSet
                      vertiCalOffset:(CGFloat)voffSet
                          upsideDown:(BOOL)upsideDown
{
    //如果需要中心对称图形上下文
    if (upsideDown) {
        //中心对称图形上下文
        [self pushContextAndRotateUpsideDown];
    }
    //牌面中心点
    CGPoint middle = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
    //返回一个实例与文本相关的字体风格和对用户的选择内容适当比例大小类别。
    UIFont *pipFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
    pipFont = [pipFont fontWithSize:[pipFont pointSize]*self.bounds.size.width*PIP_FONT_SCALE_FACTOR];
    NSAttributedString *attributedSuit = [[NSAttributedString alloc] initWithString:self.suit
                                                                         attributes:@{NSFontAttributeName:pipFont}];
    CGSize pipSize = [attributedSuit size];
    CGPoint pipDrigin = CGPointMake(middle.x-pipSize.width/2-hoffSet*self.bounds.size.width, middle.y-pipSize.height/2-voffSet*self.bounds.size.height);
    [attributedSuit drawAtPoint:pipDrigin];
    //恢复图形上下文
    if (hoffSet) {
        pipDrigin.x += hoffSet*2*self.bounds.size.width;
        [attributedSuit drawAtPoint:pipDrigin];
    }
    if (upsideDown) {
        [self popContext];
    }
}
/**
 *  绘制牌面中心区域的图案
 *
 *  @param hoffSet            水平图案间距
 *  @param voffSet            垂直图案间距
 *  @param mirroredVertically 垂直方向是否对称
 */
- (void)drawPipsWithHerizontalOffset:(CGFloat)hoffSet
                      vertiCalOffset:(CGFloat)voffSet
                  mirroredVertically:(BOOL)mirroredVertically
{
    //绘制牌面上半部分
    [self drawPipsWithHerizontalOffset:hoffSet
                        vertiCalOffset:voffSet
                            upsideDown:NO];
    if (mirroredVertically) {//如果垂直方向对称
        //绘制牌面下半部分
        [self drawPipsWithHerizontalOffset:hoffSet
                            vertiCalOffset:voffSet
                                upsideDown:YES];
    }
}
/**
 *  中心对称图形上下文
 */
- (void)pushContextAndRotateUpsideDown
{
    CGContextRef context = UIGraphicsGetCurrentContext();//获取当前图形上下文句柄
    CGContextSaveGState(context);//保存当前图形上下文
    CGContextTranslateCTM(context, self.bounds.size.width, self.bounds.size.height);//平行当前上下文的变换矩阵
    CGContextRotateCTM(context, M_PI);//旋转当前上下文的变换矩阵
}
/**
 *  恢复图形上下文
 */
- (void)popContext
{
    CGContextRestoreGState(UIGraphicsGetCurrentContext());//保存当前图形上下文
}

#pragma mark - Initialization
/**
 *  设置一些基本属性
 */
- (void)setUp
{
    self.backgroundColor = nil;//没有背景色
    self.opaque = NO;//不透明
    self.contentMode = UIViewContentModeRedraw;//如果bouns变化了,就调用drawRect
}
/**
 *  控件从xib或者stroyBoard中创建时的初始化方法
 */
- (void)awakeFromNib
{
    [self setUp];
}

@end
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值