IOS之笑脸app
ios笑脸app实现
import UIKit
@IBDesignable
class FaceView: UIView {
@IBInspectable
var lineWidth:CGFloat=3{didSet{setNeedsLayout()}}
@IBInspectable
var color:UIColor = UIColor.blueColor(){didSet{setNeedsLayout()}}
@IBInspectable
var scale:CGFloat=0.9{didSet{setNeedsLayout()}}
var faceCenter:CGPoint{
return convertPoint(center, fromView: superview)
}
var faceRadius:CGFloat{
return min(bounds.size.width, bounds.size.height)/2*scale
}
private struct Scaling {
static let FaceRadiusToEyeRadiusRatio: CGFloat = 10
//大圆半径(face半径)与小圆半径(eye半径)的比率,次数越小,小圆越大.因为 下面bezierPathForEye的方法中定义 eyeRadius = faceRadius / Scaling.FaceRadiusToEyeRadiusRatio
static let FaceRadiusToEyeOffsetRatio: CGFloat = 3
//大圆与小圆的偏移率,此数越大,小圆的圆心距大圆越近
static let FaceRadiusToEyeSeparationRatio: CGFloat = 1.5
//两个小圆之间在大圆内的分离比率
static let FaceRadiusToEyeMounthWidthRatio: CGFloat = 1
static let FaceRadiusToEyeMounthHeightRatio: CGFloat = 3
static let FaceRadiusToEyeMounthOffsetRatio: CGFloat = 3
}
private enum Eye {
case Left , Right
}
private func bezierPathForEye(whichEye: Eye) -> UIBezierPath {
//此处定义的方法为设置一只眼睛的位置,上面定义了左右眼的枚举,可通过调用.Left.Right来实现两个位置的设定
let eyeRadius = faceRadius / Scaling.FaceRadiusToEyeRadiusRatio
//定义小圆半径是大圆半径的几分之几,此处因为FaceRadiusToEyeRadiusRatio: CGFloat = 10 故为十分之一
let eyeVerticalOffset = faceRadius / Scaling.FaceRadiusToEyeOffsetRatio
//小圆的垂直偏距
let eyeHorizontalSeparation = faceRadius / Scaling.FaceRadiusToEyeSeparationRatio
//小圆的水平距离
var eyeCenter = faceCenter
eyeCenter.y -= eyeVerticalOffset
//此处相当于是用大圆圆心的y坐标减去小圆圆心的y坐标,故小圆圆心在大圆圆心之上.若为加,则在下
switch whichEye {
case .Left: eyeCenter.x -= eyeHorizontalSeparation / 2
//相当于大圆圆心的x坐标减去(小圆圆心的x坐标除以2),即在大圆圆心的左侧
case .Right: eyeCenter.x += eyeHorizontalSeparation / 2
//此处加,即在右侧
}
let path = UIBezierPath(arcCenter: eyeCenter, radius: eyeRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true) //画圆
path.lineWidth = lineWidth //设定线宽
return path
}
private func bezierPathForSmile(fractionOfMaxSmile: Double) -> UIBezierPath {
let mouthWidth = faceRadius / Scaling.FaceRadiusToEyeMounthWidthRatio
//大圆半径与线宽的比率,此处线宽=大圆半径
let mouthHeight = faceRadius / Scaling.FaceRadiusToEyeMounthHeightRatio
//mouthHeight即线的中点到圆心的距离
let mouthVerticalOffset = faceRadius / Scaling.FaceRadiusToEyeMounthOffsetRatio
let smileHeight = CGFloat(max(min(fractionOfMaxSmile, 1), -1)) * mouthHeight
//此处max(min(fractionOfMaxSmile, 1), -1)限定了笑脸指数只能在-1到1之间,fractionOfMaxSmile这个参数可以自行设定,如果设定的大于1,则只取1,设定小于-1,则只取-1
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) //设置曲线点1,此处mouthWidth / 3用于调节曲线的弧度
let cp2 = CGPoint(x: end.x - mouthWidth / 3, y: cp1.y) //设置曲线点2
let path = UIBezierPath()
path.moveToPoint(start)
path.addCurveToPoint(end, controlPoint1: cp1, controlPoint2: cp2)
path.lineWidth = lineWidth
return path
}
override func drawRect(rect: CGRect) {
let facePath=UIBezierPath(arcCenter: faceCenter, radius: faceRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)
facePath.lineWidth=lineWidth
color.set()
facePath.stroke()
bezierPathForEye(.Left).stroke()
bezierPathForEye(.Right).stroke()
let smiliness = 0.8
let smilePath = bezierPathForSmile(smiliness)
smilePath.stroke()
}
}
- IBDesignable可以在storyboard中看到自定义的uiview
- IBInspectable使属性可以改变
利用协议与代理联结数据源
protocol FaceViewDataSource:class {
func smilnessForFaceView(sender:FaceView)->Double?
}
手势识别实现缩放与改变笑脸弧度
@IBOutlet weak var faceView: FaceView!{
didSet{
faceView.dataSource=self
faceView.addGestureRecognizer(UIPinchGestureRecognizer(target: faceView, action: "scale:"))
//faceView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "changeHappiness:"))
}
}
private struct Constants{
static let HappinessGestureScale:CGFloat=4
}
@IBAction func changeHappiness(sender: UIPanGestureRecognizer) {
switch sender.state {
case .Ended:
fallthrough
case .Changed:
let translation=sender.translationInView(faceView)
let happinessChange = -Int(translation.y/Constants.HappinessGestureScale)
if happinessChange != 0{
happiness+=happinessChange
sender.setTranslation(CGPoint.zero, inView: faceView)
}
default:
break
}
}
func scale(gesture:UIPinchGestureRecognizer){
if gesture.state == .Changed{
scale*=gesture.scale
gesture.scale=1
}
}
源代码:Happiness
IOS之笑脸app的更多相关文章
- iOS高仿app源码:纯代码打造高仿优质《内涵段子》
iOS高仿app源码:纯代码打造高仿优质<内涵段子>收藏下来 字数1950 阅读4999 评论173 喜欢133 Github 地址 https://github.com/Charlesy ...
- 分分钟解决iOS开发中App启动广告的功能
前不久有朋友需要一个启动广告的功能,我说网上有挺多的,他说,看的不是很理想.想让我写一个,于是乎,抽空写了一个,代码通俗易懂,简单的封装了一下,各种事件用block回调的,有俩种样式的广告,一种是全屏 ...
- iOS UIKit:App
1.App生命周期 IOS架构是由许多设计模式实现,如model-view-controller 和 delegation模式. 1.1 main函数 与其它框架类似,IOS框架的入口也是从main函 ...
- 【HELLO WAKA】WAKA iOS客户端 之一 APP分析篇
由于后续篇幅比较大,所以调整了内容结构. 全系列 [HELLO WAKA]WAKA iOS客户端 之一 APP分析篇 [HELLO WAKA]WAKA iOS客户端 之二 架构设计与实现篇 [HELL ...
- <iOS开发>之App上架流程(2017)
本文主要介绍了App上架流程,以及上架过程中会遇到的一些问题. 一.App上架前的准备. 上架前,需要开发人员有苹果开发者账号,具体请阅读苹果开发者账号注册申请流程.本文是在已经拥有开发者账号的前提下 ...
- ios 推送app badge 数字累加操作
ios 推送app badge 数字累加操作: 一:此数字需要后台配合: 二:大致原理: 后台发推送时,第一次 传badge 为1,往后,依次累加操作即可: 当用户打开app时,app向后台发送请求, ...
- iOS 轻松使用 App 数据统计
想获取用户各项行为数据吗? 想轻松查看用户行为图表吗? 想高效进行 App 运营管理吗? 想,来我带你玩转 App 数据统计.这里我使用专业.轻便的 JAnalytics. 本文内容分为两部分:代码示 ...
- IOS研究之App转让流程须知具体介绍
网络上有非常多开发人员提问怎么转让App并想知道具体的流程.实际上Appstore的App转让流程还是比較简单的.以下特酷吧依据自己的实际操作总结下iOS Appstore中App的转让流程.供 ...
- 有谁知道什么工具测试IOS手机上APP的性能软件啊?
有谁知道什么工具测试IOS手机上APP的性能软件啊?
随机推荐
- 第四章第四个例题(LRJ)
半年了,最起码的编程能力也谈不上啊,思维神马就更不不敢说了. 互联网时代讲求效率,走得慢和不走没有区别了. The war is on. (buhuidetiduokanduodajibianyehu ...
- 关于ext3,ext4,xfs和btrfs文件系统性能对比
关于ext3,ext4,xfs和btrfs文件系统性能对比 应为原文:http://www.ilsistemista.net/index.php/linux-a-unix/6-linux-filesy ...
- [POJ1068]Parencodings
[POJ1068]Parencodings 试题描述 Let S = s1 s2...s2n be a well-formed string of parentheses. S can be enco ...
- GPS坐标互转:WGS-84(GPS)、GCJ-02(Google地图)、BD-09(百度地图)
WGS-84:是国际标准,GPS坐标(Google Earth使用.或者GPS模块)GCJ-02:中国坐标偏移标准,Google Map.高德.腾讯使用BD-09:百度坐标偏移标准,Baidu Map ...
- 30秒攻破任意密码保护的PC:深入了解5美元黑客神器PoisonTap
近日,著名硬件黑客Samy Kamkar利用5美元设备打造的黑客工具PoisonTap,只需30秒,就可以攻破设置有任意密码的电脑系统,并实现长期后门安装.PoisonTap不是暴力破解密码,而是绕过 ...
- 29 GroupSock(NetAddressList)——live555源码阅读(四)网络
29 GroupSock(NetAddressList)——live555源码阅读(四)网络 29 GroupSock(NetAddressList)——live555源码阅读(四)网络 简介 Net ...
- 数据库多对多关联表(Python&MySQL)
Python Python对MySQL数据库操作使用的是sqlalchemy这个ORM框架 #一本书可以有多个作者,一个作者又可以出版多本书 from sqlalchemy import Table, ...
- 17.2---#字棋(CC150)
牛客网的在线题.思路,比较简单.就是判断一下是否有连起来的1. public static boolean checkWon(int[][] board){ boolean res = false; ...
- JavaScript变量声明
javascript是一种无类型语言,无类型只是意味着用户不必显示地声明变量的数据类型,但是javascript仍然将根据需要自动进行数据类型转换的. javascript的数据类型可以分为简单数据类 ...
- CEF3开发者系列之进程间消息传递
在使用CEF3作为框架开发过程中,实现WebSockets.XMLHttpRequest.JS与本地客户端交互等功能时,需要在渲染(Render)进程和浏览(Browser)进程中传递消息.CEF3在 ...