[Stanford 2011] hapiness

From:view6-view7(00:17)

1.Introduction:

Implement two gestures:pinch and pan.

We first implement the pinch. We add delegate to faceView(the view) that allowed faceView to get the data,which is the degree(-1 to 1) of the smile face. Then the Controller can set self as the  delegate, and provide the smile degree(-1 to 1)  for view using the model.

Another thing is adding the pan updown gesture to control the happiness.

2. Visual Effects:

Pan:fig(1),fig(2),fig(3)

Pinch:fig(4)

3. The codes:

创建faceView的类型必须是CocoaTouch下的Obj-C class类型,创建为UIView子类

//faceView.h
#import <UIKit/UIKit.h>
@class faceView;//只是告诉编译器,faceView类是存在的,对于protocol也可以有比如@protocol FaceViewDataSource;
@protocol FaceViewDataSource<NSObject>//把faceView的笑脸程度委托给任何想要设置它的人
-(float)smileForfaceView:(faceView*)sender;//在委托的方法里,当我们获取数据和把某个东西委托给另一个东西的时候,我们几乎都会把自己(sender)传过去,因为这样就不需要再回到faceView去问。因此任何时候做一个委托或者数据源,你都会把你自己作为发送者传递过去,这和target action相类似。
//因为此句使用了faceView,而faceView在这之前还没定义,所以必须用@class faceView;声明类(即,前向引用)。
@end

@interface faceView : UIView
@property(nonatomic) CGFloat scale;  //scale表示缩放的程度,是为了实现缩放的手势,缩放和笑没有关系,所以手势的处理就放在view里,这样其他的controller也可以使用我的view的缩放功能了。
-(void)pinch:(UIPinchGestureRecognizer *)gesture; //手势处理方法是public的,因为要让所有使用faceView的人知道它有缩放功能
@property(nonatomic,weak)IBOutlet id<FaceViewDataSource> dataSource;//如果有人想控制笑脸程度,就得把自己设为FaceView的数据源
@end

//faceView.m
#import "faceView.h"
@implementation faceView
@synthesize dataSource=_dataSource;
@synthesize scale=_scale;
#define DEFAULT_SCALE 0.90  //笑脸的大小是view短边大小的90%
-(CGFloat)scale    //getter
{
     if (!_scale)
    {return DEFAULT_SCALE ;}
     else     {return _scale;}
}
-(void)setScale:(CGFloat)scale  //setter
{
      if(scale !=_scale)   //if条件表示scale改变了。为了更高效,只有在scale改变的时候才自动重绘
       {
              _scale=scale;
             [self setNeedsDisplay];
        }
}
-(void)pinch:(UIPinchGestureRecognizer *)gesture  //手势处理(这之前需要把缩放手势添加到view上,添加需要在controller里进行,处理在view里做,添加在faceView的outlet的setter里),缩放处理方法,在模拟器上用option键测试
{
      if ((gesture.state == UIGestureRecognizerStateChanged)||(gesture.state == UIGestureRecognizerStateEnded))
       {
            self.scale *= gesture.scale;
             gesture.scale = 1;  //重设scale为1,这样每次比较的就是上次的变化
        }
 }
-(void)setup
{
      self.contentMode=UIViewContentModeRedraw;//在initWithFrame和awakeFromNib里必须有此句,则在controller里自动旋转YES后,则旋转后才能重绘。
}//其实有简单的不用写代码的方法,就是在storyboard里选中view,然后在右边Attributes Inspector里Mode里选Redraw就可以了。-(void)awakeFromNib
{
    [self setup];
}
- (id)initWithFrame:(CGRect)frame  //model自动从initWithFrame开始,确保你在这里面写的东西也放到了awakeFromNib里
  {//用代码创建UIView对象,用initWithFrame做初始化;用xib创建UIView对象用awakeFromNib做其他的初始化工作. awakeFromNib是在UIVIEW中用,viewDIdLoad是在UIVIEWCONTROLLER里面用
     self = [super initWithFrame:frame];
      if (self) {
         // self.contentMode = UIViewContentModeRedraw; // 不会起作用,因为view离开storyboard之后,initWithFrame不会被调用,所以用setup方法,在awakeFromNib里调用。这样当view改变的时候就会重绘了,不管是调用init还是在view之外
        [self setup];
      }
     return self;
}
 -(void) drawCircleAtPoint:(CGPoint)p withRadius:(CGFloat)radius inContext:(CGContextRef)context
{
      UIGraphicsPushContext(context);  //子程序在修改context之前要pushContext,在最后要pop回来。可以在中间做任何事,比如改变线条颜色,这样做就不会破坏外面的context。
      CGContextBeginPath(context);
      CGContextAddArc(context, p.x, p.y, radius, 0, 2*M_PI, YES);  //开始角度0,结束角度2pai, YES表示顺时针
      CGContextStrokePath(context);    //这里没有设置线条填充颜色或线宽,需要在调用的地方设置,即drawRect
      UIGraphicsPopContext();
}
-(void)drawRect:(CGRect)rect
{
      CGContextRef context =UIGraphicsGetCurrentContext(); //需要contex来调用其他的绘图方法。
       // draw face [circle]
       CGPoint midPoint;
       midPoint.x=self.bounds.origin.x+self.bounds.size.width/2;    //  midPoint是整个view的中心点
       midPoint.y=self.bounds.origin.y+self.bounds.size.height/2;
        CGFloat size=self.bounds.size.width/2;   //找出view的短边
       if (self.bounds.size.height<self.bounds.size.width)
            size=self.bounds.size.height/2;
       size *= self.scale;    //笑脸的大小开始是整个view中短边的90%大小,后面随着scale大小来变大变小
       CGContextSetLineWidth(context, 5.0);    //设置线宽
       [[UIColor blueColor]setStroke];              //设置线条颜色
       [self drawCircleAtPoint:midPoint withRadius:size  inContext:context];  //画大圆,表示脸的轮廓
       // draw eyes [2 circle]
       #define EYE_H 0.30
       #define EYE_V 0.30
       #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];
         // no  nose
         // draw mouth  ,用贝塞尔曲线画mouth,就是在两点之间画条线,然后通过一个控制点调整这条线
         #define MOUTH_H 0.45
         #define MOUTH_V 0.40
         #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; //控制点1
          mouthCP1.x += size * MOUTH_H * 2/3;
          CGPoint mouthCP2=mouthEnd;   //控制点2
          mouthCP2.x -= size * MOUTH_H * 2/3;
          //float smile=1.0;       //smile表示移动控制点,0表示在中间,1表示控制点下移,因为下面是进行加法操作。所以1.0表示笑脸,-1.0表示哭脸
         float smile = [self.dataSource smileForfaceView:self];//使用委托
         if(smile<-1)smile = -1;
         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);      //描边
}
@end
//HappinessViewController.h
#import <UIKit/UIKit.h>
@interface HappinessViewController : UIViewController
@property (nonatomic) int happiness; // 0 is sad,100 is very happy.model里的幸福度和view里的表达方式不一样,可以演示controller如何把model翻译给view听
@end

 //HappinessViewController.m
#import "HappinessViewController.h" #import "faceView.h"
@interface HappinessViewController()<FaceViewDataSource>//私有实现此协议
@property (nonatomic,weak) IBOutlet faceView *faceView;//有了faceView(model),在controller创建一个它的outlet,然后就可以在storyboard里拖出来了。 (在storyboard里拖出通用view填充整个storyboard,在identity inspector里把它的类改成faceView,然后stroryboard里的view就是faceView了)(注意拖的时候stroryboard的view上有个黄色图标代表controller)
@end

@implementation HappinessViewController
@synthesize happiness=_happiness;
@synthesize faceView=_faceView;
-(void) setHappiness:(int)happiness//model改变,重绘view,要实现的方法

{
      _happiness=happiness;

     [self.faceView setNeedsDisplay]; //happiness一旦被设置,faceView就会被重绘。因为我们的view就是反映了幸福度。
}

-(void)setFaceView:(faceView *)faceView //在setter里添加手势识别!当系统把faceView和Controller连起来的时候,这是最佳的放置手势识别的时机。

{
     _faceView=faceView;    

     [self.faceView addGestureRecognizer:[[UIPinchGestureRecognizer alloc] initWithTarget:self.faceView  action:@selector(pinch:)]]; //这里的target就是这个手势的处理者,也就是self.faceView

     [self.faceView addGestureRecognizer:[[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handleHappinessGesture:)]];

     self.faceView.dataSource =self;//控制器把自己设置为委托

}          //添加手势识别到faceView,faceView会通过pinch来处理手势。

-(void)handleHappinessGesture:(UIPanGestureRecognizer*)gesture 

{
      if ((gesture.state==UIGestureRecognizerStateChanged)||(gesture.state==UIGestureRecognizerStateEnded))

     {
          CGPoint translation=[gesture translationInView:self.faceView];         

           self.happiness -= translation.y/2;        

          [gesture setTranslation:CGPointZero inView:self.faceView];
     }
}

-(float)smileForfaceView:(faceView *)sender //The controller,part of its job is to interpret the data in the model ,for the views.{      return (self.happiness-50)/50.0; //笑脸程度-1到1,The model‘s happiness is 0-100,此句为转化
}

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation  //实现自动旋转,但运行发现没有调用drawRect重绘,需要在faceView.m里设置initWithFrame方法

{
    return YES;
}

@end
时间: 2024-07-30 10:16:11

[Stanford 2011] hapiness的相关文章

[Stanford 2011] segue

From:view 6(00:17) Knowledge Points: 1. The segue is the thing that made it so that it moved over to the other MVC. 2. How the segue gets set up? To create a segue,you hold down ctrl and drag from the button to the other View Controller. Segues alway

[Stanford 2011] UIView、协议、手势识别

1.Autorotation 自动旋转时controller发生了什么?一是controller的view在controller允许的时候调整frame,方法shouldAutorotateToInterfaceOrientation返回controller是否允许view自动根据设备旋转而旋转.自动旋转接口包括竖直.上下颠倒.左横向和右横向这4种情况.只要在controller里实现这个方法就ok.   不管支持的是哪个方向,旋转的时候view的bound会改变,子view的frame会变,子

[Stanford 2011] Psychologist

From: view 6(00:44-) 1. Our psychologist will make a diagnosis and use the Happiness MVC to communicate it. Psychologist really has no Model(perhaps its"diagnosis",but it doesn't store it anywhere). Some MVCs are just for presenting user-interfa

Stanford iOS Learn Notes - 1

这段时间在学习Stanford的iOS 8 的教学视频,学而不思则怠,所以准备总结一下看视频学习的一些笔记,便于自己加深理解. 现在已经学了6节课,从这六节课看,前三节课主要是讲了一个Calculator的Demo,并穿插了很少一些iOS的介绍,以及MVC的介绍.第四节主要是介绍了一些Swift的语法,第五节和第六节主要讲述了iOS的触控操作,并且穿插了一些Swift的语法.因此,这篇我把篇笔记分为三部分: 总结一下教授对iOS的简介 总结一下教授在这六节课里面讲的语法 总结一下Happines

stanford推荐阅读目录

stanford推荐阅读目录 stanford deep learning 网站上推荐的阅读目录: UFLDL Recommended Readings If you're learning about UFLDL (Unsupervised Feature Learning and Deep Learning), here is a list of papers to consider reading. We're assuming you're already familiar with b

2011斯坦福大学iOS应用开发教程学习笔记(第一课)MVC.and.Introduction.to.Objective-C

2011年冬季斯坦福大学公开课 iOS应用开发教程是个很经典的教程,这个老头讲的很给力.做笔记总结. 第一课名称: MVC and Introduction to Objective-C 这课的主要内容有: iOS的概述  -什么是iOS MVC - 面向对象的概念 Objective-C-介绍下语言的概念 iOS包括四层 内核 内核是mach 4.x BSD UNIX内核 mac OS  10操作系统,是个多任务的UNIX内核,在这层上提供了网络,socket ,安全机制,文件系统,大部分这些

BZOJ2440 [中山市选2011]完全平方数

Description 小 X 自幼就很喜欢数.但奇怪的是,他十分讨厌完全平方数.他觉得这些数看起来很令人难受.由此,他也讨厌所有是完全平方数的正整数倍的数.然而这丝毫不影响他对其他数的热爱. 这天是小X的生日,小 W 想送一个数给他作为生日礼物.当然他不能送一个小X讨厌的数.他列出了所有小X不讨厌的数,然后选取了第 K个数送给了小X.小X很开心地收下了. 然而现在小 W 却记不起送给小X的是哪个数了.你能帮他一下吗? Input 包含多组测试数据.文件第一行有一个整数 T,表示测试数据的组数.

开始使用CCA CRM 2011

你可能从微软的市场动态获知我们最近发布了最新版本的Microsoft Dynamics CRM 2011的客户关怀加速器(CCA R2).CCA在一个单一的用户界面提供呼叫中心功能相结合的,能够显示和操纵来自不同业务应用程序的数据.CCA提供了许多功能,包括: l 集成代理的桌面 l 脚本以消除重复的数据输入 l 计算机电话集成(CTI) l 代理活动报告 CCA的核心是一个允许开发人员构建自己的代理的桌面,并提供多会话管理等功能的框架.UI集成不同类型的应用程序(包括Web.Windows窗体

PowerShape 2011 R3 SP1 Update Only Win32 1CD

TraceParts v2.3-ISO 1CD VisCAM.RP.v5.2.8600 1CD  Beta-CAE ANSA.v13.1.2.Win64 1CD CEI.Ensight.Gold.v9.2.2b.Linux64.Debian 1CD CEI.Ensight.Gold.v9.2.2b.MacOSX 1CD InfinySlice.v1.0.8581 1CD Leica.LISCAD.v9.0.3 1CD  AFT Impulse v4.0 2011.04.21 1CD AgroKa