UIBezierPathAndCoreGraphics


title: CoreGraphicsAndUIBezierPath
date: 2019-06-10 17:05:34
tags:

一.Core Graphics

1.简介

Core Graphics Framework是一套基于C的API框架,使用了Quartz作为绘图引擎

2.CGContextRef

图形上下文,绘图之前需要获取该上下文并传入执行渲染的函数中,有两种方式获取

2.1drawRect

*重写UIView的drawRect:方法,调用UIGraphicsGetCurrentContext()即可获得图形上下文

*drawRect:方法在view第一次显示的时候会自动调用,后面必须通过调用setNeedsDisplay或者setNeedsDisplayInRect调用

2.2UIGraphicsBeginImageContextWithOptions

*调用之后必须用UIGraphicsEndImageContext关闭上下文

3.例子

画一个蓝色圆

        UIGraphicsBeginImageContextWithOptions(CGSize(width: 100, height: 100), false, 0)

        let ctx = UIGraphicsGetCurrentContext()

        ctx?.addEllipse(in: CGRect(x: 0, y: 0, width: 100, height: 100))

        ctx?.setFillColor(UIColor.blue.cgColor)

        ctx?.fillPath()



        let image = UIGraphicsGetImageFromCurrentImageContext()

        UIGraphicsEndImageContext()


常见api见https://www.jianshu.com/p/43562a8c6c89

4.CGContextSaveGState/CGContextRestoreGState

*用于记录和用于恢复已存储的绘图上下文.

UIGraphicsBeginImageContext(CGSize(width: 100, height: 100))
let context = UIGraphicsGetCurrentContext()
//第一条线*
context?.setStrokeColor(UIColor.red.cgColor)
context?.setLineWidth(2)
context?.move(to: CGPoint(x: 10, y: 10))
context?.addLine(to: CGPoint(x: 10, y: 80))
context?.strokePath()
//储存状态
context?.saveGState()    
*//第二条*
context?.setStrokeColor(UIColor.yellow.cgColor)
context?.setLineWidth(5)
context?.move(to: CGPoint(x: 30, y: 10))
context?.addLine(to: CGPoint(x: 30, y: 80))
context?.strokePath()
//恢复状态
context?.restoreGState()
//第三条*
context?.move(to: CGPoint(x: 70, y: 10))
context?.addLine(to: CGPoint(x: 70, y: 80))
 context?.strokePath()
let image = UIGraphicsGetImageFromCurrentImageContext()


在这里插入图片描述

5.UIGraphicsPushContext/UIGraphicsPopContext

*用于完全更改图形上下文和恢复之前的图形上下文.

*要看切换新的绘图context后,是要继续使用CoreGraphics绘制图形,还是要使用UIKit,前者不需要使用这两个api,后者需要

*CGContextSaveGState是压栈当前的绘制状态,而UIGraphicsPushContext:压栈当前的绘制对象,生成新的绘制图层

6.关于uiimage的一些操作

*调用uiimage的draw方法将UIImage绘制在当前的上下文中

6.1平移

let image = UIImage(named: "icon_label_home_pre")
let size = image?.size
UIGraphicsBeginImageContextWithOptions(CGSize(width: (size?.width)! * 2, height: (size?.height)!), false, 1)
image?.draw(at: CGPoint(x: 0, y: 0))
image?.draw(at: CGPoint(x: (size?.width)!, y: 0))
let newimage = UIGraphicsGetImageFromCurrentImageContext()   


6.2缩放

let image = UIImage(named: "icon_label_home_pre")
let size = image?.size
UIGraphicsBeginImageContextWithOptions(CGSize(width: (size?.width)! * 2, height: (size?.height)! * 2), false, 1)
image?.draw(in: CGRect(x: 0, y: 0, width: (size?.width)! * 2, height: (size?.height)! * 2))
let newimage = UIGraphicsGetImageFromCurrentImageContext()


*放大会变模糊

6.3裁剪

let image = UIImage(named: "icon_label_home_pre")
let size = image?.size
UIGraphicsBeginImageContextWithOptions(CGSize(width: (size?.width)! / 2, height: (size?.height)!), false, 1)
image?.draw(in: CGRect(x: -(size?.width)!/2, y: 0, width: (size?.width)!, height: (size?.height)!))
let newimage = UIGraphicsGetImageFromCurrentImageContext()


得到图片的右半边

7.CGImage

在这里插入图片描述

let image = UIImage(named: "icon_label_home_pre")
let size = image?.size

// 调用cropping对cgimage进行裁剪(对应oc中的CGImageCreateWithImageInRect)
let left = image?.cgImage?.cropping(to: CGRect(x: 0, y: 0, width: (size?.width)! / 2, height: (size?.height)!))
let right = image?.cgImage?.cropping(to: CGRect(x: (size?.width)! / 2, y: 0, width: (size?.width)! / 2, height: (size?.height)!))

UIGraphicsBeginImageContextWithOptions(CGSize(width: (size?.width)! * 1.5, height: (size?.height)!), **false**, 1)
let context = UIGraphicsGetCurrentContext()
//绘制
context?.draw(left!, in: CGRect(x: 0, y: 0, width: (size?.width)! / 2, height: (size?.height)!))
context?.draw(right!, in: CGRect(x: (size?.width)!, y: 0, width: (size?.width)! / 2, height: (size?.height)!))

let newimage = UIGraphicsGetImageFromCurrentImageContext()


*将图片分成两半 绘制在上下文的两边

*当前坐标系坐标原点在左上角, 目标上下文坐标系在左下角,所以绘制出来是上下颠倒的

在这里插入图片描述
*解决办法是调用contenxt.draw方法再绘制一次

let image = UIImage(named: "icon_label_home_pre")
let size = image?.size
let left = image?.cgImage?.cropping(to: CGRect(x: 0, y: 0, width: (size?.width)! / 2, height: (size?.height)!))
let right = image?.cgImage?.cropping(to: CGRect(x: (size?.width)! / 2, y: 0, width: (size?.width)! / 2, height: (size?.height)!))
UIGraphicsBeginImageContextWithOptions(CGSize(width: (size?.width)! * 1.5, height: (size?.height)!), false, 1)
let context = UIGraphicsGetCurrentContext()

 context?.draw(flip(img: left!), in: CGRect(x: 0, y: 0, width: (size?.width)! / 2, height: (size?.height)!))
context?.draw(flip(img: right!), in: CGRect(x: (size?.width)!, y: 0, width: (size?.width)! / 2, height: (size?.height)!))

let newimage = UIGraphicsGetImageFromCurrentImageContext()


再绘制一次的方法

func flip(img: CGImage) -> CGImage {
        let size = CGSize(width: img.width, height: img.height)
        UIGraphicsBeginImageContextWithOptions(CGSize(width: (size.width), height: (size.height)), false, 1)
        let context = UIGraphicsGetCurrentContext()
        context?.draw(img, in: CGRect(x: 0, y: 0, width: (size.width), height: (size.height)))
        let newimage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return (newimage?.cgImage)!
   }


在这里插入图片描述

二、CIFilter与CIImage

*使用之前要将CoreImage框架导入

*CIFilter,一个滤镜对象至少要有一个输入参数,并产生一个输出图片

*CIContext,通过它Core Image可以绘制一个CIFilter产生的结果

let image = UIImage(named: "icon_label_home_pre")
let imageCI = CIImage(cgImage: (image?.cgImage)!)
let grad = CIFilter(name: "CIRadialGradient")
let center = CIVector(x: (image?.size.width)! / 2.0, y: (image?.size.height)! / 2.0)

// 使用setValue:forKey:方法设置滤镜属性
//从白到黑的渐变方式滤镜进行处理
grad?.setValue(center, forKey: "inputCenter")

// 在指定滤镜名时提供所有滤镜键值对*
let dark = CIFilter(name: "CIDarkenBlendMode", parameters: ["inputImage": grad?.outputImage, "inputBackgroundImage": imageCI])

//CIDarkenBlendMode的作用是背景图片样本将被源图片的黑色部分替换掉

let c = CIContext()
let moi = c.createCGImage((dark?.outputImage)!, from: imageCI.extent)
let moi4 = UIImage(cgImage: moi!, scale: (image?.scale)!, orientation: (image?.imageOrientation)!)

let myImageView = UIImageView()
myImageView.image = moi4
myImageView.frame = CGRect(x: 100, y: frameY, width: (moi4.size.width), height: (moi4.size.height))
frameY += (moi4.size.height)
frameY += 20
self.view.addSubview(myImageView)


在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三、UIBezierPath+CAShapeLayer

*UIBezierPath是对CGPathRef数据类型的封装

*绘制以下图案

在这里插入图片描述

UIGraphicsBeginImageContext(CGSize(width: 200, height: 200))
let p = UIBezierPath()
// 绘制一个黑色的垂直黑色线,作为箭头的杆子*
p.move(to: CGPoint(x: 100, y: 100))
p.addLine(to: CGPoint(x: 100, y: 19))
p.lineWidth = 20
p.stroke()
// 绘制一个红色三角形箭头*
UIColor.red.set()
p.removeAllPoints()
p.move(to: CGPoint(x: 80, y: 25))
p.addLine(to: CGPoint(x: 100, y: 0))
p.addLine(to: CGPoint(x: 120, y: 25))
p.fill()
// 从箭头杆子上裁掉一个三角形,使用清除混合模式
p.removeAllPoints()
p.move(to: CGPoint(x: 90, y: 101))
p.addLine(to: CGPoint(x: 100, y: 90))
p.addLine(to: CGPoint(x: 110, y: 101))
 p.fill(with: .clear, alpha: 1)
let image = UIGraphicsGetImageFromCurrentImageContext()
 UIGraphicsEndImageContext()


*画一个只有左上角和右上角有圆角的矩型

在这里插入图片描述

UIGraphicsBeginImageContext(CGSize(width: 200, height: 200))
let context = UIGraphicsGetCurrentContext()
context?.setStrokeColor(UIColor.black.cgColor)
context?.setLineWidth(3)
let path = UIBezierPath(roundedRect: CGRect(x: 100, y: 100, width: 100, height: 100), byRoundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 100, height: 100))
path.stroke()
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()


*绘制二次贝塞尔曲线 一个控制点

在这里插入图片描述

UIGraphicsBeginImageContext(CGSize(width: 200, height: 200))
UIColor.red.set()
let path = UIBezierPath()
path.lineWidth = 2
path.move(to: CGPoint(x: 0, y: 200))
path.addQuadCurve(to: CGPoint(x: 200, y: 200), controlPoint: CGPoint(x: 0, y: 10))
path.stroke()
let image = UIGraphicsGetImageFromCurrentImageContext()


*绘制三次贝塞尔曲线 两个控制点

在这里插入图片描述

UIGraphicsBeginImageContext(CGSize(width: 200, height: 200))
UIColor.red.set()
let path = UIBezierPath()
path.lineWidth = 2
path.move(to: CGPoint(x: 0, y: 200))
path.addCurve(to: CGPoint(x: 200, y: 100), controlPoint1: CGPoint(x: 100, y: 10), controlPoint2: CGPoint(x: 150, y: 100))
path.stroke()
let image = UIGraphicsGetImageFromCurrentImageContext()


**一般,UIBezierPath配合CAShapeLayer一起使用.UIBezierPath给CAShapeLayer提供路径,CAShapeLayer在提供的路径中进行渲染,绘制出了Shape

let layer = CAShapeLayer()
layer.frame = CGRect(x: 0, y: 610, width: 100, height: 100)
layer.backgroundColor = UIColor.cyan.cgColor
layer.strokeColor = UIColor.black.cgColor
layer.fillColor = UIColor.red.cgColor
self.view.layer.addSublayer(layer)


在这里插入图片描述
设置的描边色与填充色没有作用

需要UIBezierPath来绘制路径,然后使用CAShapeLayer进行渲染

let path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 100, height: 100))

layer.path = path.cgPath


在这里插入图片描述
*实现三次贝塞尔曲线动画

let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 200))
path.addCurve(to: CGPoint(x: 200, y: 100), controlPoint1: CGPoint(x: 100, y: 10), controlPoint2: CGPoint(x: 150, y: 100))

let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = 5
animation.fromValue = 0
animation.toValue = 1
animation.repeatCount = 100
        
let layer = CAShapeLayer()
layer.strokeColor = UIColor.red.cgColor
layer.fillColor = UIColor.white.cgColor
layer.frame = CGRect(x: 200, y: 410, width: 200, height: 200)
self.view.layer.addSublayer(layer)

layer.path = path.cgPath
layer.lineWidth = 2
layer.strokeStart = 0
layer.strokeEnd = 1      

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
      layer.add(animation, forKey: **nil**)
}


四、CAGradientLayer

CAGradientLayer是CALayer的一个子类,用来生成渐变色的Layer

五、参考链接

UIImage的一些简单操作https://www.jianshu.com/p/3baddf100b67

UIBezierPath和Core Graphicshttps://www.cnblogs.com/wanghuaijun/p/5870699.html

苹果文档https://developer.apple.com/library/archive/samplecode/QuartzDemo/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007531

CGContextSaveGState与UIGraphicsPushContexthttps://www.jianshu.com/p/be38212c0f79

使用UIBezierPath绘制图形 https://www.cnblogs.com/zhouxihi/p/6253296.html)https://www.cnblogs.com/zhouxihi/p/6253296.html

iOS绘图教程http://www.cnblogs.com/xdream86/archive/2012/12/12/2814552.html

iOS 绘图使用总结 Core Graphics常见api https://www.jianshu.com/p/43562a8c6c89

https://www.jianshu.com/p/139f4fbe7b6b iOS开发之CAShapeLayer初探

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值