標籤:ios開發 手勢識別 struts xcode 斯坦福
轉載請註明出處
http://blog.csdn.net/pony_maggie/article/details/27845257
作者:小馬
五 程式碼範例
上面講到的知識點在這個樣本都有涉及。另外我這裡也只是分析部分重要的代碼,更多的知識瞭解請自行下載代碼(文章最下面有地址)並結合公開課一起看。
建立一個single view的工程,然後新增一個視圖類,叫FaceView,如所示:
然後我們在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幫我自動計算,如下所示:
然後再來看一下效果,
這個似乎也不是我們想要的,它自動展開了,我們還需要加一些代碼調整,橫屏時要重繪笑臉。
- (void)setup{ //UIViewContentModeRedraw可以使旋轉螢幕時調用drawRect self.contentMode = UIViewContentModeRedraw;}- (void)awakeFromNib{ [self setup];}
這樣再來看看效果:
現在我們來添加手勢識別,讓這個笑臉支援縮放功能。
需要在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:)]];
看看效果:
接下來繼續添加功能,我們用代理和上下滑動的手勢識別來實現通過上下滑動來控制笑臉的微笑程度。
手勢識別好理解,為什麼要用代理呢?可以這樣理解,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