第五课内容: 自动旋转、 Protocols、 手势识别、一个自定义UIView的Demo
1、自动旋转
当设备旋转时,你的controller会做什么呢?你可以控制界面是否和设备一起一起旋转。
- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
- {
- return UIInterfaceOrientationIsPortrait(orientation);
- return YES;
- return (orientation != UIInterfaceOrientationPortraitUpsideDown);
- }
当旋转的时候,view的bounds会改变,子view的frame,子view的子view也会改变。
改变的规则是:struts和springs。
当view的bound改变时,drawRect不会默认调用
红色的
I
就是struts,中间的红色箭头就是springs。
右边红白色的显示屏似的就是用动画告诉你view如何改变。白色的是父view,红色的是你选中的view。
这个控制在iPhone上一般使用不到,因为屏幕太小了。
幸运的是,有UIView有这么个属性来控制
三种控制方式:
1、
- @property (nonatomic) UIViewContentMode contentMode;
- UIViewContentMode{Left,Right,Top,Right,BottomLeft,BottomRight,TopLeft,TopRight}
2、缩放的控制属性:
- UIViewContentModeScale{ToFill,AspectFill,AspectFit}
分别是填充,内容填充,内容适应。 toFill是默认的模式,它会自动缩放像素点填满新的空间,可能会造成图形扭曲。
3、
- @property (nonatomic) CGRect contentStretch;
指定某一个区域拉伸
初始化一个UIView.
2、协议procotol
- @protocol Foo <Other, NSObject>
- - (void)doSomething;
- @optional
- - (int)getSomething;
- - (void)doSomethingOptionalWithArgument:(NSString *)argument;
- @required
- - (NSArray *)getManySomethings:(int)howMany;
- @property (nonatomic, strong) NSString *fooProp;
- @end
可以定义在自己的头文件里,也可以定义在其他类的头文件中。
实现协议,并使用的语法:
- #import “Foo.h” // importing the header file that declares the Foo @protocol
- @interface MyClass : NSObject <Foo>
- ...
- @en
- id <Foo> obj = [[MyClass alloc] init];
- @property (nonatomic, weak) id <Foo> myFooProperty;
协议的主要作用:
实现委托和数据源。
委托几乎都是weak的,因为被设置为委托的对象通常都是委托对象的所有者或创建者。
比如controller通常把自己设置成view的委托或数据源,你不要它们相互的strong指针指向。
scrollView例子
- @protocol UIScrollViewDelegate
- @optional
- - (UIView *)viewForZoomingInScrollView:(UIScrollView *)sender;
- - (void)scrollViewDidEndDragging:(UIScrollView *)sender willDecelerate:(BOOL)decelerate;
- @end
- @interface UIScrollView : UIView
- @property (nonatomic, weak) id <UIScrollViewDelegate> delegate;
- @end
- @interface MyViewController : UIViewController <UIScrollViewDelegate>
- @property (nonatomic, weak) IBOutlet UIScrollView *scrollView;
- @end
- @implementation MyViewController
- - (void)setScrollView:(UIScrollView *)scrollView {
- _scrollView = scrollView;
- self.scrollView.delegate = self;
- }
- - (UIView *)viewForZoomingInScrollView:(UIScrollView *)sender { return ... };
- @end
3、手势识别
如何获得触摸事件呢?
得到触摸时间的通知
相应预定义好的手势
UIGestureRecognizer类,它是个抽象类,需要实现。
使用手势识别有两步骤:
先创建一个手势,把它附到UIView上,然后当手势被识别时进行处理。
第一步由controller来完成
第二步由UIView自己完成
从controller添加一个手势到UIView:
- - (void)setPannableView:(UIView *)pannableView
- {
- _pannableView = pannableView;
- UIPanGestureRecognizer *pangr =
- [[UIPanGestureRecognizer alloc] initWithTarget:pannableView action:@selector(pan:)];
- [pannableView addGestureRecognizer:pangr];
- }
target 是手势识别之后的处理者,这里就是view本身。
UIPangestureRecognizer的三个方法:
- - (CGPoint)translationInView:(UIView *)aView;
- - (CGPoint)velocityInView:(UIView *)aView;
- - (void)setTranslation:(CGPoint)translation inView:(UIView *)aView;
第一个告诉移动的距离
第二个告诉移动的速度
第三个是重新设置
手势识别的状态机
- @property (readonly) UIGestureRecognizerState state;
状态从possible 如果手势比较短:recognized 如果持续:Began - Changed ,最后Ended
还有Failed 和 Cancelled状态,取消或其他操作中断时会有这个情况。
pan:是什么样的呢:
- - (void)pan:(UIPanGestureRecognizer *)recognizer
- {
- if ((recognizer.state == UIGestureRecognizerStateChanged) ||
- (recognizer.state == UIGestureRecognizerStateEnded)) {
- CGPoint translation = [recognizer translationInView:self];
-
-
- self.origin = CGPointMake(self.origin.x+translation.x, self.origin.y+translation.y);
- [recognizer setTranslation:CGPointZero inView:self];
- }
- }
其他实例的手势:
UIPinchGestureRecognizer 缩放
UIRotationGestureRecognizer 旋转手势,两个手指按下,然后旋转,是个弧度,不是角度。
UISwipeGestureRecognizer 滑动手势, 一个或多个手指滑动,
UITapGestureRecognizer 点击手势
4、一个幸福笑脸的Demo:
内容介绍:
Model是: int happiness
View是:自定义的view叫做FaceView
Controller是:HappinessViewController
观察内容有:
drawRect 包括绘制子程序, pop push context(环境)
Faceview委托的数据如何属于Controller的协议。
Controller处理手势,或者view处理手势
通过手势来改变幸福度。
用整数表示幸福度, 0表示悲伤, 100表示非常幸福。
有两个手势,一个被view处理,因为它只修改显示,另外一个被controller处理,它要修改model,修改幸福度。
主要源码:
happinessViewController.h
- #import <UIKit/UIKit.h>
-
- @interface HappinessViewController : UIViewController
-
- @property (nonatomic) int happiness;
-
- @end
happinessViewController.m
- #import "HappinessViewController.h"
- #import "FaceView.h"
-
- @interface HappinessViewController() <FaceViewDataSource>
- @property (nonatomic, weak) IBOutlet FaceView *faceView;
- @end
-
- @implementation HappinessViewController
-
- @synthesize happiness = _happiness;
- @synthesize faceView = _faceView;
-
- - (void)setHappiness:(int)happiness
- {
- _happiness = happiness;
- [self.faceView setNeedsDisplay];
- }
-
- - (void)setFaceView:(FaceView *)faceView
- {
- _faceView = faceView;
-
- [self.faceView addGestureRecognizer:[[UIPinchGestureRecognizer alloc] initWithTarget:self.faceView action:@selector(pinch:)]];
- [self.faceView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleHappinessGesture:)]];
- self.faceView.dataSource = self;
- }
-
- - (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
- {
- return (self.happiness - 50) / 50.0;
- }
-
- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
- {
- return YES;
- }
-
- @end
FaceView.h
- #import <UIKit/UIKit.h>
-
- @class FaceView;
-
- @protocol FaceViewDataSource
- - (float)smileForFaceView:(FaceView *)sender;
- @end
-
- @interface FaceView : UIView
-
- @property (nonatomic) CGFloat scale;
-
- - (void)pinch:(UIPinchGestureRecognizer *)gesture;
-
-
-
- @property (nonatomic, weak) IBOutlet id <FaceViewDataSource> dataSource;
-
- @end
FaceView.m
- #import "FaceView.h"
-
- @implementation FaceView
-
- @synthesize dataSource = _dataSource;
- @synthesize scale = _scale;
-
- #define DEFAULT_SCALE 0.90
-
- - (CGFloat)scale
- {
- if (!_scale) {
- return DEFAULT_SCALE;
- } else {
- return _scale;
- }
- }
-
- - (void)setScale:(CGFloat)scale
- {
- if (scale != _scale) {
- _scale = scale;
- [self setNeedsDisplay];
- }
- }
-
- - (void)pinch:(UIPinchGestureRecognizer *)gesture
- {
- if ((gesture.state == UIGestureRecognizerStateChanged) ||
- (gesture.state == UIGestureRecognizerStateEnded)) {
- self.scale *= gesture.scale;
- gesture.scale = 1;
- }
- }
-
- - (void)setup
- {
- self.contentMode = UIViewContentModeRedraw;
- }
-
- - (void)awakeFromNib
- {
- [self setup];
- }
-
- - (id)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- [self setup];
- }
- return self;
- }
-
- - (void)drawCircleAtPoint:(CGPoint)p withRadius:(CGFloat)radius inContext:(CGContextRef)context
- {
- UIGraphicsPushContext(context);
- CGContextBeginPath(context);
- CGContextAddArc(context, p.x, p.y, radius, 0, 2*M_PI, YES);
- CGContextStrokePath(context);
- UIGraphicsPopContext();
- }
-
- - (void)drawRect:(CGRect)rect
- {
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- CGPoint midPoint;
- 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.40
- #define MOUTH_SMILE 0.25
-
- CGPoint mouthStart;
- mouthStart.x = midPoint.x - MOUTH_H * size;
- mouthStart.y = midPoint.y + MOUTH_V * size;
- CGPoint mouthEnd = mouthStart;
- mouthEnd.x += MOUTH_H * size * 2;
- CGPoint mouthCP1 = mouthStart;
- mouthCP1.x += MOUTH_H * size * 2/3;
- CGPoint mouthCP2 = mouthEnd;
- mouthCP2.x -= MOUTH_H * size * 2/3;
-
- 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, mouthCP2.y, mouthCP2.x, mouthCP2.y, mouthEnd.x, mouthEnd.y);
- CGContextStrokePath(context);
- }
-
- @end
容芳志 (http://blog.csdn.net/totogo2010)
本文遵循“署名-非商业用途-保持一致”创作公用协议