转载请注明出处

http://blog.csdn.net/pony_maggie/article/details/27845257

作者:小马

五 代码演示样例

上面讲到的知识点在这个演示样例都有涉及。另外我这里也仅仅是分析部分重要的代码,很多其它的知识了解请自行下载代码(文章最以下有地址)并结合公开课一起看。

新建一个single view的project。然后新增一个视图类。叫FaceView,例如以下图所看到的:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9ueV9tYWdnaWU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

然后我们在storyboard里拖进来一个通用的视图控件。作为上面那个视图类相应的视图,例如以下图所看到的:

     

接着要做视图控制器类里添加这个FaceView的oulet以便我们能够操作视图。例如以下:

開始关注代码了。

我们打算在FaceView画一个笑脸,来反映幸福的程序,一个笑脸由以下几部分组成:

脸的轮廓(一个大圆)

眼睛(两个小圆)

嘴巴(贝塞尔曲线)

好,代码例如以下:

- (void)drawCircleAtPoint:(CGPoint)p withRadius:(CGFloat)radius inContext:(CGContextRef)context
{
//设置成当前的context
//使用UIKit来进行随意画图。你会希望保存当前的UIKit上下文。包含全部已经绘制的内容,
//接着切换到一个全新的画图上下文中
UIGraphicsPushContext(context);
CGContextBeginPath(context);
CGContextAddArc(context, p.x, p.y, radius, 0, 2*M_PI, YES);
CGContextStrokePath(context);
UIGraphicsPopContext();
} //This method is called when a view is first displayed or when an event occurs that invalidates a visible part of the view
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext(); //draw face (circle)
//draw eyes (2 circles)
//no nose
//mouth (Bézier curve)
CGPoint midPoint; //注意这里,由于画圆本身是基于faceView自己,所以计算坐标也是相对于faceView,所以要用bounds下的坐标
//当我们把faceView在storyboard里拉下一些。然后用frame对照看效果就非常明显了
midPoint.x = self.bounds.origin.x + self.bounds.size.width/2;
midPoint.y = self.bounds.origin.y + self.bounds.size.height/2; CGFloat size = self.bounds.size.width/2; //大圆半径
if (self.bounds.size.height < self.bounds.size.width) {
size = self.bounds.size.height/2;
}
size *= self.scale; //设置线条宽度和颜色等
CGContextSetLineWidth(context,5.0);
[[UIColor blueColor] setStroke];
[self drawCircleAtPoint:midPoint withRadius:size inContext:context]; #define EYE_H 0.35
#define EYE_V 0.35
#define EYE_RADIUS 0.10 CGPoint eyePoint;
eyePoint.x = midPoint.x - size * EYE_H;
eyePoint.y = midPoint.y - size * EYE_V;
[self drawCircleAtPoint:eyePoint withRadius:size*EYE_RADIUS inContext:context];
eyePoint.x += size * EYE_H * 2;
[self drawCircleAtPoint:eyePoint withRadius:size*EYE_RADIUS inContext:context]; #define MOUTH_H 0.45
#define MOUTH_V 0.45
#define MOUTH_SMILE 0.25 //弯曲的比例。微笑的程度 CGPoint mouthStart;
mouthStart.x = midPoint.x - size * MOUTH_H;
mouthStart.y = midPoint.y + size * MOUTH_V;
CGPoint mouthEnd = mouthStart;
mouthEnd.x += size * MOUTH_H * 2; CGPoint mouthCP1 = mouthStart;
mouthCP1.x += size * MOUTH_H * 2/3;
CGPoint mouthCP2 = mouthEnd;
mouthCP1.x -= size * MOUTH_H * 2/3; float smile = [self.dataSource smileForFaceView:self];
if (smile < -1)
{
smile = -1;
}
else if (smile > 1)
{
smile = 1;
} CGFloat smileOffset = MOUTH_SMILE * size * smile;
mouthCP1.y += smileOffset;
mouthCP2.y += smileOffset; CGContextBeginPath(context);
CGContextMoveToPoint(context, mouthStart.x, mouthStart.y);
CGContextAddCurveToPoint(context, mouthCP1.x, mouthCP1.y, mouthCP2.x, mouthCP2.y, mouthEnd.x, mouthEnd.y);
CGContextStrokePath(context); }

先上个图看一下效果:

这里有一点要注意,我们须要考虑横屏的情况,由于我是在xcode5环境下写的代码,就不用老师进的Struts and springs了,直接加约束。让storyboard帮我自己主动计算,例如以下所看到的:

  

然后再来看一下效果。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9ueV9tYWdnaWU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

这个似乎也不是我们想要的,它自己主动拉伸了,我们还须要加一些代码调整,横屏时要重绘笑脸。

- (void)setup
{
//UIViewContentModeRedraw能够使屏幕旋转时调用drawRect
self.contentMode = UIViewContentModeRedraw;
} - (void)awakeFromNib
{
[self setup];
}

这样再来看看效果:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9ueV9tYWdnaWU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

如今我们来加入手势识别。让这个笑脸支持缩放功能。

须要在facView和根控制器里增加对应的代码。facView里:

//手势识别,缩放功能
- (void)pinch:(UIPinchGestureRecognizer *)gesture
{
if ((gesture.state == UIGestureRecognizerStateChanged) ||
(gesture.state == UIGestureRecognizerStateEnded))
{
/*
以下两行代码事实上和这一行效果是一样的,所以注意理解第二行置1的作用.能够查一下gesture.scale是怎么取值的
self.scale = gesture.scale;
*/
self.scale *= gesture.scale;
NSLog(@"scale:%f", gesture.scale);
gesture.scale = 1;
}
}

然后在根控制器里:

[self.faceView addGestureRecognizer:[[UIPinchGestureRecognizer alloc] initWithTarget:self.faceView action:@selector(pinch:)]];

看看效果:

     

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9ueV9tYWdnaWU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

接下来继续加入功能。我们用代理和上下滑动的手势识别来实现通过上下滑动来控制笑脸的微笑程度。

手势识别好理解,为什么要用代理呢?能够这样理解。FaceView里的这个笑脸。是通过一个幸福指数(controller里的happiness)来控制。这个幸福指数是一个数据源。那FaceView是一个视图,视图本身是不能拥有数据源的。所以要把controller作为代理管理数据源。

以下是代码。

加入手势识别

加入一个上下滑动的手势。注意target不是faceView而是controller,所以处理函数也在controller里实现, UIPanGestureRecognizer主要用于拖动,就是捕捉手指的位移

[self.faceView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleHappinessGesture:)]];
self.faceView.dataSource = self; //把控制器设为代理

注意以下inView后面都是指定self.faceView作为參数。这个參数的意义是你打算让这个手势转换在哪个坐标系工作。当然是我们的FaceView了

- (void)handleHappinessGesture:(UIPanGestureRecognizer *)gesture
{
if ((gesture.state == UIGestureRecognizerStateChanged) ||
(gesture.state == UIGestureRecognizerStateEnded))
{
CGPoint translation = [gesture translationInView:self.faceView];//转换成坐标系中的点位移变化
self.happiness -= translation.y / 2; //除2的作用时,降低变化的幅度
[gesture setTranslation:CGPointZero inView:self.faceView];//置0能够让变化幅度不累加
}
}

接下来实现协议中定义的函数,

- (float)smileForFaceView:(FaceView *)sender
{
return (self.happiness - 50)/50.0;//happiness是0~100, 微笑程度是-1~1,须要转换
}

使用代理的位置

float smile = [self.dataSource smileForFaceView:self];
if (smile < -1)
{
smile = -1;
}
else if (smile > 1)
{
smile = 1;
}

模拟器下执行,会发现随着鼠标的上下拖动。笑脸的微笑程度会变化。

代码下载地址:

https://github.com/pony-maggie/Happiness

斯坦福IOS开发第五课(第二部分)的更多相关文章

  1. 斯坦福IOS开发第五课(第一部分)

    转载请注明出处 http://blog.csdn.net/pony_maggie/article/details/27706991 作者:小马 因为第五课的内容比較多.分两部分来写. 一 屏幕旋转基本 ...

  2. iOS开发 ReactiveCocoa入门教程 第二部分

    ReactiveCocoa 是一个框架,它允许你在你的iOS程序中使用函数响应式(FRP)技术.加上第一部分的讲解,你将会学会如何使用信号量(对事件发出数据流)如何替代标准的动作和事件处理逻辑.你也会 ...

  3. 从零开始学ios开发(五):IOS控件(2),Slider

    下面继续学习ios的其他控件,这次会使用到的控件有Slider,当然还有一些之前已经使用过的控件Label. 这次我们不新建一个project了,当然如果你愿意重新创建一个新的项目也完全可以,我们还是 ...

  4. 【Web探索之旅】第二部分第五课:响应式网站和移动应用

    内容简介 1.第二部分第五课:响应式网站和移动应用 2.第三部分第一课预告:服务器 第二部分第五课:响应式网站和移动应用 在我们开始聊响应式网站之前,我们可以聊聊移动App(App是Applicati ...

  5. iOS开发之窥探UICollectionViewController(五) --一款炫酷的图片浏览组件

    本篇博客应该算的上CollectionView的高级应用了,从iOS开发之窥探UICollectionViewController(一)到今天的(五),可谓是由浅入深的窥探了一下UICollectio ...

  6. 斯坦福大学 iOS 开发公开课总结

     斯坦福大学 iOS 开发公开课总结   前言 iPhone 开发相关的教程中最有名的,当数斯坦福大学发布的 "iPhone 开发公开课 " 了.此公开课在以前叫做<iPho ...

  7. ios专题 - 斯坦福大学iOS开发公开课总结

    转自:http://blog.devtang.com/blog/2012/02/05/mvc-in-ios-develop/ 前言 iphone开发相关的教程中最有名的,当数斯坦福大学发布的”ipho ...

  8. 【C语言探索之旅】 第二部分第五课:预处理

    内容简介 1.课程大纲 2.第二部分第五课: 预处理 3.第二部分第六课预告:   创建你自己的变量类型 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语 ...

  9. 【Linux探索之旅】第二部分第五课:用户和权限,有权就任性

    内容简单介绍 .第二部分第五课:用户和权限,有权就任性 2.第二部分第六课预告:Nano,刚開始学习的人的文本编辑器 用户和权限.有权就任性 今天的标题也挺任性的啊,虽说小编是一个非常本分的人(真的吗 ...

随机推荐

  1. 【转】TCP/IP详解学习笔记(一)

      TCP/IP详解学习笔记   这位仁兄写得太好了. http://blog.csdn.net/goodboy1881/category/204448.aspx TCP/IP详解学习笔记(13)-T ...

  2. Struts2(七)基础小结

    一.struts2和action 二.Result 三.struts.xml 四.namespace 第一种绝对路径 <form action="${pageContext.reque ...

  3. CentOS 下安装MySQL 默认源为5.1版本

    CentOS——默认为安装5.1版本,如果需要安装5.5版本,需要使用remi源 yum install mysql-server –enablerepo=remi   Ubuntu——默认为安装5. ...

  4. atitit.提升开发效率---MDA 软件开发方式的革命(3)----自己主动化建表

    atitit.提升开发效率---MDA 软件开发方式的革命(3)----自己主动化建表 1. 建模在后自己主动建表 1 1. 传统上,须要首先建表,在业务编码.. 1 2. 模型驱动建表---很多其它 ...

  5. 使用Nginx限制同一IP的访问频率

    http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html http://nginx.org/en/docs/http/ngx_http ...

  6. Android API之android.provider.ContactsContract.Data

    android.provider.ContactsContract.Data Constants for the data table, which contains data points tied ...

  7. 【mysql】Innodb三大特性之adaptive hash index

    1.Adaptive Hash Indexes 定义 If a table fits almost entirely in main memory, the fastest way to perfor ...

  8. MSSQL-SQL SERVER一些使用中的技巧

    获取前一天时间"getdate() - 1" 获取上一小时时间"dateadd(hour, -1, getdate())" order by field1, f ...

  9. PHP-Ajax跨域解决方案

    1.先了解下Ajax跨域问题: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "ht ...

  10. HDUOJ-------(1022)Train Problem I

    Train Problem I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...