热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【Swift】使用贝塞尔曲线绘制表情

2019独角兽企业重金招聘Python工程师标准1、创建一个基于UIView名为FaceView的类我们不直接在HappinessViewController(根视图控制器)

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

1、创建一个基于UIView名为FaceView的类

        我们不直接在HappinessViewController(根视图控制器) 中实现,而是将FaceView完全独立出来,这正是遵循了MVC的设计原则。我们主要通过贝塞尔曲线来实现表情的绘制。

        注:@IBDesignable:Xcode6 的发布,苹果为开发者构建自定义控件推出了新功能IBDesignable和IBInspectable,允许在IB中实时预览设计成果。这会给实际开发提升很高效率。IBDesignable作用在于可以使改视图在IB中实时预览。

//可以在IB中预览
@IBDesignable
class FaceView: UIView
{}

2、定义属性

         定义线宽、线颜色、缩放系数

         特别的:我另外定义了一个自定义参数——幸福指数。他的范围是-1~1。        

         注:@IBInspectable:将自定义的属性在IB中显示,以便我们更方便的控制其属性,达到动态预览的效果。

@IBInspectable
//线的宽度
var lineWidth : CGFloat = 3 { didSet {setNeedsDisplay() } }@IBInspectable
//线的颜色
var color : UIColor = UIColor.blueColor() { didSet {setNeedsDisplay() } }@IBInspectable
//表情缩放系数
var scale : CGFloat = 0.90 {didSet { setNeedsDisplay() } }@IBInspectable
//微笑程度(幸福指数)
var smiliness : Double = 0.75 {didSet { setNeedsDisplay() } }

3、采用结构体来规定固定参数

           我们采用结构体来规定我们想要的参数。如下所示:

private struct Scaling {static let FaceRadiusToEyeRadiusRatio:CGFloat = 10//眼睛弯曲半径比例static let FaceRadiusToEyeOffsetRatio:CGFloat = 3//眼睛偏移比例static let FaceRadiusToEyeSeparationRatio:CGFloat = 1.5//眼睛间隙比例static let FaceRadiusToMouthWidthRatio:CGFloat = 1//嘴宽度比例static let FaceRadiusToMouthHeightRatio:CGFloat = 3//嘴高度比例static let FaceRadiusToMouthOffsetRatio:CGFloat = 3//嘴便宜比例
}

4、设计一个枚举,代表眼睛的左、右

private enum Eye { case Left, Right }

5、两个get属性

       faceCenter:计算在父视图的中心坐标。

//在父视图上的中心坐标
var faceCenter:CGPoint {get{return convertPoint(center, fromView: superview)}
}

        faceRadius:表情的缩放系数

var faceRadius:CGFloat {get{return scale * min(bounds.size.width,bounds.size.height) / 2}
}

6、先画圆圆的脸

        当然是先画脸(圆),通过UIBezierPath类方法来画(创建路径对象)一个圆(路径)。

//arcCenter: 圆心
//radius:半径
//startAngle:起点角度
//endAngle:终点角度
let facePath = UIBezierPath(arcCenter: faceCenter, radius: faceRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)

        设置颜色宽度。

//线的宽度
facePath.lineWidth = lineWidth
//线的颜色
color.set()

        最后别忘了调用stroke(),将这个路径画出来。

//最终将它"画"出来
facePath.stroke()

7、其次是画眼睛:

        我们封装一下画眼睛这部分代码,通过传入眼睛左右的枚举值来画。  眼睛实质还是画圆,只是不是完整的圆,我们只需要根据左右找到其中心、半径及起始角度就好了。

//眼睛private func bezierPathForEye(whichEye: Eye) -> UIBezierPath{//计算眼睛的半径let eyeRadius = faceRadius/Scaling.FaceRadiusToEyeRadiusRatio//计算眼睛垂直的偏移量let eyeVerticalOffset = faceRadius/Scaling.FaceRadiusToEyeOffsetRatio//计算眼睛水平的距离let eyeHorizontalSeparation = faceRadius/Scaling.FaceRadiusToEyeSeparationRatio//眼睛中心var eyeCenter = faceCenter//y值是一致的eyeCenter.y -= eyeVerticalOffset//根据左右来计算 眼的圆心x坐标switch whichEye {case .Left: eyeCenter.x -= eyeHorizontalSeparation / 2case .Right: eyeCenter.x += eyeHorizontalSeparation / 2}//调用上面用过的UIBezierPath画圆的类方法来画圆let path = UIBezierPath(arcCenter: eyeCenter, radius: eyeRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)//线的宽path.lineWidth = lineWidth//最后返回路径return path}

8、最后画嘴

        嘴可以用曲线来画。使用UIBezierPath对象的方法:addCurveToPoint,来画曲线。需要计算的值有、起始点、控制点。

//微笑private func bezierPathForSmile(fractionOfMaxSmile : Double) -> UIBezierPath{//嘴宽let mouthWidth = faceRadius/Scaling.FaceRadiusToMouthWidthRatio//嘴高let mouthHeight = faceRadius/Scaling.FaceRadiusToMouthHeightRatio//嘴垂直偏移let mouthVerticalOffset = faceRadius/Scaling.FaceRadiusToMouthOffsetRatio//微笑高度let smileHeight = CGFloat(max(min(fractionOfMaxSmile, 1), -1)) * mouthHeight//开始点let start = CGPoint(x: faceCenter.x - mouthWidth / 2, y: faceCenter.y + mouthVerticalOffset)//结束点let end = CGPoint(x: start.x + mouthWidth, y: start.y)//第一个控制点let cp1 = CGPoint(x: start.x + mouthWidth / 3, y: start.y + smileHeight)//第二个控制点let cp2 = CGPoint(x: end.x - mouthWidth / 3, y: cp1.y)let path = UIBezierPath()//路径移至起点path.moveToPoint(start)//增加路径的终点、控制点path.addCurveToPoint(end, controlPoint1: cp1, controlPoint2: cp2)path.lineWidth = lineWidthreturn path}

        其中控制点cp1、cp2可以通过下图来理解:

194856_biFO_2279344.jpeg

9、重绘视图

        在重绘中调用以上方法,具体如下:

override func drawRect(rect: CGRect){//圆圆的脸let facePath = UIBezierPath(arcCenter: faceCenter, radius: faceRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)facePath.lineWidth = lineWidthcolor.set()facePath.stroke()//一双大眼bezierPathForEye(.Left).stroke()bezierPathForEye(.Right).stroke()//嘴let smilePath = bezierPathForSmile(smiliness)smilePath.stroke()}

10、运行结果如下:

195626_DYkb_2279344.png        

11、不够幸福?好吧好像是幸福指数不够!

        打开SB(故事版)、点击FaceView,可以在右侧属性栏中看到,我们自定义的属性已经绑定在右边了,我们可以手动更改,在IB中实时预览输出效果!像下面这样:

200243_pasq_2279344.png试着更改一下宽度,我改为20,发下脸皮真的变厚了呢?

200433_MrkU_2279344.png

 

试着更改颜色,我改为黑色,好吧我们都不喜欢黑脸!

200600_vUrP_2279344.png

试着改一下缩放比例,改为0.5,好吧脸变小了:

200725_xwYp_2279344.png

 

最后我们试着调一下,幸福指数:

我们发现幸福指数为1的时候是这样的:

201022_dMZu_2279344.png

0变成了直线,而-1变成了难过的表情:

201134_IYRa_2279344.png

201142_Kz6L_2279344.png

最后希望大家幸福指数都是1 !!!!

Github:

https://github.com/ly918/Demos


转:https://my.oschina.net/Misayalvyuan/blog/713517



推荐阅读
  • imnewtotheswiftandxcodeworld,soimhavingaproblemtryingtointegrateapackagetomypro ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 十大经典排序算法动图演示+Python实现
    本文介绍了十大经典排序算法的原理、演示和Python实现。排序算法分为内部排序和外部排序,常见的内部排序算法有插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。文章还解释了时间复杂度和稳定性的概念,并提供了相关的名词解释。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 去掉空格的方法——Python工程师招聘标准与实践
    本文介绍了去掉空格的方法,并结合2019独角兽企业招聘Python工程师的标准与实践进行讨论。同时提供了一个转载链接,链接内容为更多相关信息。 ... [详细]
  • iOS Swift中如何实现自动登录?
    本文介绍了在iOS Swift中如何实现自动登录的方法,包括使用故事板、SWRevealViewController等技术,以及解决用户注销后重新登录自动跳转到主页的问题。 ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
  • Postgresql备份和恢复的方法及命令行操作步骤
    本文介绍了使用Postgresql进行备份和恢复的方法及命令行操作步骤。通过使用pg_dump命令进行备份,pg_restore命令进行恢复,并设置-h localhost选项,可以完成数据的备份和恢复操作。此外,本文还提供了参考链接以获取更多详细信息。 ... [详细]
  • 本文介绍了ASP.NET Core MVC的入门及基础使用教程,根据微软的文档学习,建议阅读英文文档以便更好理解,微软的工具化使用方便且开发速度快。通过vs2017新建项目,可以创建一个基础的ASP.NET网站,也可以实现动态网站开发。ASP.NET MVC框架及其工具简化了开发过程,包括建立业务的数据模型和控制器等步骤。 ... [详细]
  • ps:写的第一个,不足之处,欢迎拍砖---只是想用自己的方法一步步去实现一些框架看似高大上的小功能(比如说模型中的toArraytoJsonsetAtt ... [详细]
author-avatar
育诚家瑋逸群
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有