UIView---汇总

视图、绘图、贴图、手势、变形、布局、动画、动力、特效 UIBezierPath、UIGestureRecognizer、CGAffineTransform、frame、bounds、center、transform、UITouch、UIEvent、Layout、Autoresizing、Auto Layout、Animation、UIImage、NSTimer、UIView、Core Animation、CALayer、CAAnimation、CABasicAnimation、CAKeyframeAnimation、CAAnimationGroup、CATransform3D、UIDynamicAnimator、UIGravityBehavior、UICollisionBehavior、UIAttachmentBehavior、 UISnapBehavior、UIPushBehavior、NSNotification ========================================================================================================= 知识点 1、绘图 今天: 1.绘图 1.1基本概念 屏幕:不少个晶体组成的,分辨率1920X1080,一行有1920个晶体,一共有1080行,每个晶体发三种颜色的光(red,green,blue) 图片: 点阵图:一堆点,每个点是一个颜色,图片的分辨率指的就是存储的图片的点的个数 图片中的每个点是用4个整数来存储的,这四个整数分别对象该点的red(0-255)、green(0-255),blue(0-255),alpha。一个点就须要4个字节来存储,依据这个规律就能够计算图片的大小了。但为了压缩图片的大小,将一个点周围的四个点计算一个平均值,用一个点的值来代替这四个点, 矢量图: 存储的是生成图形所须要通过计算的数学公式,因此放大后不会失真 像素 2.OC对象与图形的转换 内存中的OC对象,会基于系统提供的默认规则,绘制成平面图后显示到屏幕上。 绘制的过程本质是由底层的Core Graphics 这一组C语言的API实现 系统为编程人员提供了一个可编程的接口,在指定的位置添加绘制的代码之后,就可让系统在原有的绘制基础上增长自定义的绘制内容 3.绘图的实现 [Demo1_Graphics] 实现步骤: a。重写UIView的drawRect方法。该方法由系统自动调用,不能本身手动调用。由于drawRect方法只是系统一整套绘制流程中的一个环节。 b。获取绘制的上下文对象 c。设置上下文对象的绘制起始点 d。添加路径 e。设置描边或填充的颜色 f。绘制路径 MyView.h 继承自UIView MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { // 获取系统的上下文对象
    CGContextRef context = UIGraphicsGetCurrentContext(); CGContextMoveToPoint(context, 40, 40); CGContextAddLineToPoint(context, 40, 140); CGContextAddLineToPoint(context, 140, 40); CGContextAddLineToPoint(context , 40, 40); //设置描边的颜色
 CGContextSetStrokeColorWithColor(context , [[UIColor redColor] CGColor]); CGContextSetFillColorWithColor(context, [[UIColor greenColor]CGColor]); //按照路径描边 //CGContextStrokePath(context); //CGContextFillPath(context);
 CGContextDrawPath(context, kCGPathFillStroke); } @end MyViewController.h MyViewController.m #import "MyViewController.h"
#import "MyView.h"

@interface MyViewController () @end

@implementation MyViewController - (void)viewDidLoad { [super viewDidLoad]; MyView *view = [[MyView alloc]initWithFrame:self.view.frame]; 将自定义的view加到controller view.backgroundColor = [UIColor whiteColor]; [self.view addSubview:view]; }  4. UIBezierPath贝塞尔曲线 4.1 是OC语言对c语言绘图的一部分API的封装结果 4.2 做用:更方便的绘制直线、曲线、矩形、圆弧、椭圆等 4.3 绘制直线 【Demo2_BezierPath_Line】 path.lineWidth 设置线条宽度 path.lineCapStyle = kCGLineCapButt;设置线头儿的样式 path.lineJoinStyle = kCGLineJoinRound;设置交叉点的样式 [[UIColor redColor] setStroke];设置线条颜色 [[UIColor greenColor] setFill];设置填充色 1)在故事板中拉入一个view,并在第三个检查器class与本身建立的类关联起来 2)建立贝塞尔路径实例 UIBezierPath *path = [UIBezierPath bezierPath]; 3)绘制,填充颜色、线条显示出来 [path stroke]; [path fill]; MyView.h MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { //建立贝塞尔路径的实例
    UIBezierPath *path = [UIBezierPath bezierPath]; [path addArcWithCenter:CGPointMake(120, 120) radius:50 startAngle:M_PI_2 endAngle:M_PI clockwise:YES]; [path addLineToPoint:CGPointMake(50, 50)]; //移动到起始点 //[path moveToPoint:CGPointMake(50, 50)]; //[path addLineToPoint:CGPointMake(50, 150)]; //[path addLineToPoint:CGPointMake(200, 50)]; //[path addLineToPoint:CGPointMake(50, 50)]; //设置颜色
 [[UIColor redColor] setStroke]; [[UIColor greenColor] setFill]; //设置path的经常使用属性
    path.lineWidth = 10; //设置线头儿的样式 //path.lineCapStyle = kCGLineCapButt; //设置交叉点的样式 //path.lineJoinStyle = kCGLineJoinRound; //绘制
 [path stroke]; //[path fill]; 
} 4.4绘制圆弧 【Demo2_BezierPath_Line】 M_PI_2 M_PI [path addArcWithCenter:CGPointMake(120, 120) radius:50 startAngle:M_PI_2 endAngle:M_PI clockwise:YES]; 练习: 定制圆形的下载进度提示条 【Demo3_Custom_DownloadView】 // 重绘视图
 [self setNeedsDisplay]; DownloadView.h DownloadView.m #import "ViewController.h"
#import "DownloadView.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet DownloadView *downloadView; @property (weak, nonatomic) IBOutlet UISlider *slider; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.slider.value = 0; } - (IBAction)downloadNumber:(UISlider *)sender { self.downloadView.progressValue = sender.value; } DownloadView.h #import <UIKit/UIKit.h>

@interface DownloadView : UIView @property(nonatomic,strong)UIColor *progressColor; @property(nonatomic)CGFloat progressValue;//0~1之间的浮点数

@end DownloadView.m #import "DownloadView.h"

@implementation DownloadView //重写setter方法
- (void)setProgressValue:(CGFloat)progressValue{ // 保留原有的set方法的操做
    _progressValue = progressValue; // 重绘视图
 [self setNeedsDisplay]; } - (void)drawRect:(CGRect)rect { UIBezierPath *path = [UIBezierPath bezierPath]; //圆显示在屏幕中心
    CGPoint center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); [path addArcWithCenter:center radius :(self.bounds.size.width-20)/2 startAngle:M_PI_2*3 endAngle:self.progressValue*2*M_PI+M_PI_2*3 clockwise:YES]; if (self.progressColor) {//设置了即为设置后的颜色,若是没设置就显示默认的蓝色
 [self.progressColor setStroke]; }else{ [[UIColor blueColor] setStroke]; } path.lineWidth = 8; [path stroke]; } @end   4.5绘制曲线 【Demo4_BezierPath_Curve】 MyView.h MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(140, 40)]; 起始坐标 第一个拉伸的点 [path addCurveToPoint:CGPointMake(40, 180) controlPoint1:CGPointMake(40, 40) controlPoint2:CGPointMake(140, 180)]; [path addCurveToPoint:CGPointMake(140, 320) controlPoint1:CGPointMake(140, 180) controlPoint2:CGPointMake(40, 320)]; [[UIColor redColor] setStroke]; path.lineWidth = 6; [path stroke]; } @end4.6绘制其余图形 (矩形,圆形,椭圆) 【Demo5_BezierPath_Others】 MyView.h MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { //绘制圆角矩形 // UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(40, 40, 200, 150) cornerRadius:10]; //圆形
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(40, 40, 200, 200)]; [[UIColor redColor] setStroke]; [[UIColor greenColor] setFill]; path.lineWidth = 8; [path fill]; [path stroke]; } @end  5.绘制字符串 【Demo6_Draw_String】 使用NSString带有的绘制方法完成: drawAtPoint: drawInRect: 根据字符串的内容计算对应的高度: boundingRectWithSize: MyView.h MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { NSString *str = @"Hello World"; //设置字符串的格式
    NSDictionary *strAttributes = @{ NSFontAttributeName:[UIFont systemFontOfSize:24], NSForegroundColorAttributeName:[UIColor redColor] }; [str drawAtPoint:CGPointMake(40, 40) withAttributes:strAttributes]; //长字符串的绘制
    NSString *str2 = @"looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog String"; //计算出该字符串所占的空间大小 //计算字符串的高
    CGRect strRect = [str2 boundingRectWithSize:CGSizeMake(250, 999) options:2 attributes:strAttributes context:nil]; [str2 drawInRect:CGRectMake(40, 80,250,strRect.size.height) withAttributes:strAttributes]; } @end6.绘制图片 【Demo7_Draw_Image】 UIImage *image = [UIImage imageNamed:@"icon80.png"]; [image drawAtPoint:CGPointMake(50, 50)];//按图片原始大小显示
    [image drawInRect:imageRect];//根据设定的范围对图片进行缩放
MyView.h MyView.m #import "MyView.h"

@implementation MyView - (void)drawRect:(CGRect)rect { CGRect imageRect = CGRectMake(50, 50, 200, 200); UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:imageRect]; //按照路径剪切
 [path addClip]; UIImage *image = [UIImage imageNamed:@"icon80.png"]; //[image drawAtPoint:CGPointMake(50, 50)];
 [image drawInRect:imageRect]; } @end  做业: 1.参考资源1,绘制聊天气泡 写一个视图类:MessageView +message:NSString 要求: a。只作保持在视图右上角的状况 b。最宽不能超过200,高度根据消息的内容来计算 ViewController.h #import <UIKit/UIKit.h>

@interface ViewController : UIViewController @end ViewController.m #import "ViewController.h"
#import "TRMessageView.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; TRMessageView *view = [[TRMessageView alloc]initWithMessage:@"中文测试一下总体到了屏幕的右侧会是什么样子呢?"]; view.frame = CGRectMake(0, 20, 320, view.height); [self.view addSubview:view]; TRMessageView *view2 = [[TRMessageView alloc]initWithMessage:@"你来我往的对话中,为何会有一条灰色的这么难看的横线显示在哪里呢?"]; view2.frame = CGRectMake(0, 20+view.height, 320, view2.height); [self.view addSubview:view2]; } @end TRMessageView.h #import <UIKit/UIKit.h>

@interface TRMessageView : UIView @property(nonatomic,readonly)CGFloat height; -(instancetype)initWithMessage:(NSString *)message; @end TRMessageView.m #import "TRMessageView.h"

@interface TRMessageView() @property(nonatomic,strong)NSString *message; @property(nonatomic)CGFloat messageWidth; @property(nonatomic)CGFloat messageHeight; @property(nonatomic,readwrite)CGFloat height; @end


@implementation TRMessageView -(instancetype)initWithMessage:(NSString *)message{ self = [super init]; if (self) { self.message = message; CGRect msgRect = [self.message boundingRectWithSize:CGSizeMake(200, 999) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{ NSFontAttributeName:[UIFont systemFontOfSize:15] } context:nil]; self.messageWidth = msgRect.size.width; self.messageHeight = msgRect.size.height; self.height = 40+self.messageHeight; self.backgroundColor = [UIColor whiteColor]; } return self; } - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); //绘制气泡
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(280-self.messageWidth, 10, self.messageWidth+20, self.messageHeight+20) cornerRadius:10]; [path moveToPoint:CGPointMake(300, self.messageHeight+20)]; [path addLineToPoint:CGPointMake(310, 30+self.messageHeight)]; [path addLineToPoint:CGPointMake(290, 30+self.messageHeight)]; [[UIColor lightGrayColor] setFill]; [path fill]; CGContextRestoreGState(context); CGContextSaveGState(context); //绘制字符串
    [self.message drawInRect:CGRectMake(290-self.messageWidth, 20, self.messageWidth, self.messageHeight) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15],NSForegroundColorAttributeName:[UIColor whiteColor]}]; } @end2.绘制饼图 写一个视图类: PieChartView +radius:CGFloat半径 +width:CGFloat 线宽 +data:NSArray数据 +[item]: PieChartViewItem PieChartViewItem +color:UIColor 颜色 +value:CGFloat  0~1 占整体的百分比 TRPieChartViewItem.h #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface TRPieChartViewItem : NSObject @property(nonatomic,strong)UIColor *color; @property(nonatomic)CGFloat value; -(instancetype)initWithColor:(UIColor *)color andValue:(CGFloat)value; @end TRPieChartViewItem.m #import "TRPieChartViewItem.h"

@implementation TRPieChartViewItem - (instancetype)initWithColor:(UIColor *)color andValue:(CGFloat)value{ self = [super init]; if (self) { self.color = color; self.value = value; } return self; } @end TRPieChartView.h #import <UIKit/UIKit.h>

@interface TRPieChartView : UIView @property(nonatomic)CGFloat radius; @property(nonatomic)CGFloat lineWidth; @property(nonatomic,strong)NSArray *data; @end TRPieChartView.m #import "TRPieChartView.h"
#import "TRPieChartViewItem.h"

@implementation TRPieChartView -(NSArray *)data{ if (!_data) { TRPieChartViewItem *item1 = [[TRPieChartViewItem alloc]initWithColor:[UIColor redColor] andValue:0.25]; TRPieChartViewItem *item2 = [[TRPieChartViewItem alloc]initWithColor:[UIColor blueColor] andValue:0.5]; TRPieChartViewItem *item3 = [[TRPieChartViewItem alloc]initWithColor:[UIColor blackColor] andValue:0.15]; TRPieChartViewItem *item4 = [[TRPieChartViewItem alloc]initWithColor:[UIColor greenColor] andValue:0.1]; _data = @[item1,item2,item3,item4]; } return _data; } -(CGFloat)lineWidth{ if (!_lineWidth) { _lineWidth = 10; } return _lineWidth; } -(CGFloat)radius{ if (!_radius) { _radius = 100; } return _radius; } - (void)drawRect:(CGRect)rect { CGFloat startAngel = M_PI_2*3; for (TRPieChartViewItem *item in self.data) { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); UIBezierPath *path = [UIBezierPath bezierPath]; // 画弧线
        [path addArcWithCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/2) radius:self.radius startAngle:startAngel endAngle:(item.value*2*M_PI+startAngel) clockwise:YES]; startAngel +=item.value*2*M_PI; //画直线
        [path addLineToPoint:CGPointMake(self.frame.size.width/2, self.frame.size.height/2)]; //线宽
        path.lineWidth = self.lineWidth; path.lineCapStyle = kCGLineCapButt; //填充色
 [item.color setFill]; //线条颜色 //[[UIColor grayColor] setStroke]; //绘制填充边线
 [path fill]; //[path stroke];
 CGContextRestoreGState(context); CGContextSaveGState(context); } } @end3.自定义Cell,图片是圆角的 新闻客户端中的自定义Cell,里面的图片作成圆角的 =============================================================== 知识点 2、贴图、美化 1. iOS的设备的种类 1.1设备的分辨率和坐标系大小(2倍关系) 1.2Retina屏设备对图片的处理 a。程序中的图片:在不一样尺寸的图片名称上添加@2x 或 @3x这样的标识便可。系统会根据当前设备的不一样,来选择加载哪一个版本的图片 b。AppIcon应用程序图标:屏幕上有一个尺寸,设置界面上也有图标,搜索结果中也有图标,设定图片资源库中的AppIcon里面不一样尺寸的图片后,完成设置 2、9切片技术 2.1 为何须要9切片(9 Slice技术) 用代码来实现基于一个简单图片,产生不一样尺寸的图片的一种手段 2.2切片原则 4个角不变,中间部分能够横向或纵向拉伸或复制 两种模式:Tile 切片复制 (默认模式) Stretch切片拉伸 2.3 实现方法 a。利用xcode工具中的图片资源库中的9切片功能 b。编写代码实现切片 如: #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *btnImageView; 和故事版中的image连线 @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *btnImage = [[UIImage imageNamed:@"delete_btn"] resizableImageWithCapInsets:UIEdgeInsetsMake(9, 12, 9, 12) resizingMode:UIImageResizingModeStretch]; 编代码实现九切片功能 self.btnImageView.image = btnImage; } @end

3. 对控件的贴图美化 3.1 UIButton 四种状态的设置:经过代码或故事板 四种状态的切换: Normal:正常 Highlighted:高亮,按下后不抬起的状态 Selected:经过修改selected属性设置 .selected=YES(按钮被选中) Disabled:经过修改enabled属性设置 .enabled=NO(按钮不可用状态) - (IBAction)changeState:(UIButton *)sender { 将按钮连线,用代码修改 [self.button setSelected:!sender.selected];//连续点击,持续变化 // [sender setSelected:YES];//是否改变,只变化一次 //sender setEnabled:YES // 按钮摆在那不动:normal // 点下,不抬起:highLighted // 点下,松手:normal // 进入到seleted状态:用代码修改seleted属性 // enabled状态:用代码改
} 以下:view+image+button+field,经过故事板实现便可,不须要编程  3.2 UISlider setMaximumTrackImage:设置滑动过的区域的背景图 setMinimumTrackImage:设置未滑动到的区域的背景图 setThumbImage:设置滑块中拖动按钮部分的图片 如: - (void)viewDidLoad { [super viewDidLoad]; [self.slider setMaximumTrackImage:[[UIImage imageNamed:@"playing_volumn_slide_foreground"] resizableImageWithCapInsets:UIEdgeInsetsMake(4, 4, 4, 4) resizingMode:UIImageResizingModeTile]forState:UIControlStateNormal]; [self.slider setMinimumTrackImage:[UIImage imageNamed:@"playing_volumn_slide_bg"] forState:UIControlStateNormal]; [self.slider setThumbImage:[UIImage imageNamed:@"playing_volumn_slide_sound_icon"] forState:UIControlStateNormal]; } 4. tintColor 统一管理一个视图中全部子视图和子视图的子视图的颜色,批量修改一些视图的颜色 1.颜色受控制的因素 拥有 xxxTintColor属性,如UISwitch,可使用属性修改 没有xxxTintColor,受从UIView中继承来的tintColor影响 2.self.window.tintColor影响整个应用的风格,除非某一个视图特别设置了本身的tintColor颜色 5. UIAppearance 遵照此协议的对象,能够批量设置某种控件的外观(颜色、贴图等)(只针对某一类控件) 1.获取方式 +(instancetype)appearance; 2.使用方式 拿到此对象后,经过这个对象设置背景、颜色等来批量设置某一类控件的外观 [ [ UISlider appearance] setTintColor: [ UIColor redColor ] ] 如: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[UISlider appearance]setTintColor:[UIColor purpleColor]]; [[UIButton appearance]setBackgroundImage:[UIImage imageNamed:@"delete_btn"] forState:UIControlStateNormal]; return YES; } 6. UINavigationBar美化 6.1 设置NavigationBar的颜色 //设置导航栏的背景色
            naviBar.barTintColor = [UIColor blackColor]; //设置是否透明
        naviBar.translucent = YES; 6.2 给NavigationBar贴图 //设置背景图(图片的高度,竖屏时通常设置为64个点,横屏时高度是52个点)
    [naviBar setBackgroundImage:[UIImage imageNamed:@"NavigationBarDefault"] forBarMetrics:UIBarMetricsDefault];竖屏显示 [naviBar setBackgroundImage:[UIImage imageNamed:@"NavigationBarLandscapePhone"] forBarMetrics:UIBarMetricsLandscapePhone];横屏显示 6.3 设置返回按钮的图片 naviBar.backIndicatorImage = [UIImage imageNamed:@"back_btn"]; naviBar.backIndicatorTransitionMaskImage =[UIImage imageNamed:@"back_btn"]; naviBar.tintColor = [UIColor redColor];设置按钮颜色 6.4 设置标题栏的文字字体 naviBar.titleTextAttributes = @{ NSFontAttributeName:[UIFont boldSystemFontOfSize:24], NSForegroundColorAttributeName:[UIColor redColor] }; 6.5 设置标题为任意视图 UIStepper *stepper = [[UIStepper alloc]init]; self.navigationItem.titleView = stepper; 6.6 设置状态栏风格 (显示电池栏的风格) //重写方法,用于设置状态的风格
- (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; } 6.7 是否显示状态栏 //重写方法,设置状态栏隐藏
- (BOOL)prefersStatusBarHidden { return YES; } 6.8 隐藏NavigationBar [self.navigationController setNavigationBarHidden:!self.navigationController.navigationBarHidden animated:YES]; ViewController.h ViewController.m #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UINavigationBar *naviBar = self.navigationController.navigationBar; naviBar.barTintColor = [UIColor blackColor]; naviBar.translucent = YES; //设置背景图
    [naviBar setBackgroundImage:[UIImage imageNamed:@"NavigationBarDefault"] forBarMetrics:UIBarMetricsDefault]; [naviBar setBackgroundImage:[UIImage imageNamed:@"NavigationBarLandscapePhone"] forBarMetrics:UIBarMetricsLandscapePhone]; //设置返回按钮的的图片
    naviBar.backIndicatorImage = [UIImage imageNamed:@"back_btn"]; naviBar.backIndicatorTransitionMaskImage =[UIImage imageNamed:@"back_btn"]; naviBar.tintColor = [UIColor redColor]; //设置标题栏的文字字体
    naviBar.titleTextAttributes = @{ NSFontAttributeName:[UIFont boldSystemFontOfSize:24], NSForegroundColorAttributeName:[UIColor redColor] }; //设置标题为其余视图 //UITextField *textField = [[UITextField alloc]init];
    UIStepper *stepper = [[UIStepper alloc]init]; self.navigationItem.titleView = stepper; } - (IBAction)hideNavigationBar:(UIButton *)sender { [self.navigationController setNavigationBarHidden:!self.navigationController.navigationBarHidden animated:YES]; } @end GreenViewController.h GreenViewController.m #import "GreenViewController.h"

@interface GreenViewController () @end

@implementation GreenViewController //重写方法,用于设置状态的风格
- (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; } //重写方法,设置状态栏隐藏
- (BOOL)prefersStatusBarHidden { return YES; }    点击item获得的界面 7. UITableViewCell的背景贴图 实现步骤: a。故事板中修改TableView的分割线(Separator)为None b。故事板中修改TableViewCell的背景色(Background)为clearColor c。cell.backgroundView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"list"]]; cell.selectedBackgroundView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"listSeleted”]];选中后的背景图设置显示 如: MyTableViewController.h MyTableViewController.m #import "MyTableViewController.h" 
@interface MyTableViewController () @end

@implementation MyTableViewController - (void)viewDidLoad { [super viewDidLoad]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 10; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; cell.textLabel.text = @"Hello World"; cell.backgroundView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"list"]]; cell.selectedBackgroundView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"listSelected"]]; return cell; }  格显示的是虚线 做业: 聊天气泡: 用9slicing实现 类:MessageView +message:NSString +fromMe:BOOL +messageLabel:UILabel +messagePopImageView:UIImageView//图,切片
 效果: a。屏幕最上方添加一个文本框和一个发送按钮 b。屏幕下方已经存在一些聊天的消息,其中本身说的内容在屏幕右侧,对方说的内容在屏幕的左侧 c。在文本框中输入内容后,算做本身说的内容,而后点击发送按钮,在界面中追加一个气泡,在屏幕的右侧,里面显示文本框中输入的内容,而且键盘收起,文本框内容清空 -(void)refresh{ if(fromMe) 显示蓝色的气泡在右上角 大小根据message属性计算 else 显示灰色的气泡在左上角 大小,计算 } 参考:H02资源包 追加:看Apple官方的NavigationBar的demo ===================================================================== 知识点 3、手势(UIGestureRecognizer)、变形 1.手势(GestureRecognizer) 1.1什么是手势 用户在view上的一些触屏操做,诸如 点、滑动、捏合。。。 1.2 手势的分类 a。一次性手势 触屏动做发生之后,方法只会响应一次。如:点击如下屏幕、解锁动做 b。连续性手势 触屏动做发生之后,方法会连续响应屡次。如:长按、捏合、移动、旋转 1.3 手势的本质 本质是一个对象,当用户针对视图发生了必定的动做以后,系统会检测到该动做,并根据具体的动做建立不一样种类的手势对象,该对象中会存储与动做有关的一些数据,如触屏动做的坐标点、滑动的快慢、移动的距离。 若是发生的是一次性手势动做,那么就调用一次方法,若是发生的是连续性手势动做,那么就屡次调用响应方法 1.4 如何使用手势 step1:建立手势对象 step2:设置与该种手势相关的属性 step3:将手势对象与须要检测的视图关联在一块儿 1.5 具体的手势种类 全部手势的父类:UIGestureRecognizer 6种手势: UIXXXGestureRecognizer UITapGestureRecognizer 点击一下屏幕 UISwipeGestureRecognizer 轻扫屏幕,如解锁 UIPinchGestureRecognizer 捏合手势 UIPanGestureRecognizer 移动手势 UILongPressGestureRecognizer 长按手势 UIRotationGestureRecognizer 旋转手势 2.具体的手势使用 2.1 UITapGestureRecognizer (一次性手势) 【Demo1_TapGestureRecognizer】 经常使用属性: .numberOfTapsRequired 设置点击数 手指点几下 .numberOfTouchesRequired 设置触点数 几个手指点击 CGPoint location=[gr locationInView:self.view];获取点击动做时,出点的绝对坐标 ViewController.m #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //step1 建立手势对象
    UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)]; //step2 设置手势的属性
    tapGR.numberOfTapsRequired = 1; tapGR.numberOfTouchesRequired = 1; //step3 将手势与视图关联起来
 [self.view addGestureRecognizer:tapGR]; } -(void)tap:(UITapGestureRecognizer *)gr { CGPoint location = [gr locationInView:self.view]; NSLog(@"(%.2f,%.2f)",location.x,location.y); } @end

    2.2 UISwipeGestureRecognizer(一次性手势) 【Demo2_SwipeGestureRecognizer】 经常使用属性: .numberOfTouchesRequired触点的个数 .direction 轻扫的方向 注意:direction属性为枚举值,而且是能够进行组合的枚举值,多个枚举值之间使用 “|”按位“或”进行运算。 补充:1<<? 表达式的含义是:对于二进制的数字1进行向左移位,符号右侧是几,就向左移动几位。 ViewController.m #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UISwipeGestureRecognizer *swipeGR = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipe:)]; swipeGR.numberOfTouchesRequired = 1; //设置轻扫动做的方向
    swipeGR.direction = UISwipeGestureRecognizerDirectionLeft|UISwipeGestureRecognizerDirectionRight; [self.view addGestureRecognizer:swipeGR]; } -(void)swipe:(UISwipeGestureRecognizer *)gr{ NSLog(@"swipe... ..."); } @end

    2.3 UILongPressGestureRecognizer(连续性手势) 【Demo3_LongPressGestureRecognizer】 经常使用属性: longGR.minimumPressDuration = 1;//设置最少按下的持续时间
 ViewController.m #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UILongPressGestureRecognizer *longGR = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)]; //设置最少按下的持续时间
    longGR.minimumPressDuration = 1; [self.view addGestureRecognizer:longGR]; } -(void)longPress:(UILongPressGestureRecognizer *)gr{ NSLog(@"long press... ..."); } @end

    2.4 UIPinchGestureRecognizer(连续性手势,捏合) 【Demo4_PinchGestureRecognizer】 CGFloat scale = gr.scale; //手势的变化比率,向外扩展时,为大于1的数,向内捏合时,为小与1的数
   CGFloat velocity = gr.velocity;//手势的变化速率,向外扩展时,为正数,向内捏合时,为负数
 以上两个属性不是用来设置的,而是在手势发生时用来读取的。 练习: 界面上 有一个UITextView,看小说,增长手势识别,若是快速扩,小说出现,快速捏,小说隐藏,速度不快时,表明放大或缩小小说的文字大 ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UITextView *textView;//连线

@end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.textView.editable = NO; UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)]; [self.view addGestureRecognizer:pinchGR]; } -(void)pinch:(UIPinchGestureRecognizer *)gr{ CGFloat scale = gr.scale;比率 CGFloat velocity = gr.velocity; 速率 //NSLog(@"scale=%.2f,velocity=%.2f",scale,velocity);
    if (velocity > 6) { self.textView.hidden = NO; } else if (velocity < -6){ self.textView.hidden = YES; } else{ // 改变字体
        self.textView.font = [UIFont systemFontOfSize:17*scale]; } } 2.5 UIRotationGestureRecognizer (连续性手势,旋转) 【Demo5_RotationGestureRecognizer】 经常使用属性: CGFloat rotation = gr.rotation; 表明手势旋转的弧度。顺时针旋转时,为正数,逆时针旋转时为负数 ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView;//image上添加图片

@end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIRotationGestureRecognizer *rotationGR = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotation:)]; [self.view addGestureRecognizer:rotationGR]; } -(void)rotation:(UIRotationGestureRecognizer *)gr{ //CGFloat rotation = gr.rotation; //NSLog(@"%.2f",rotation); //实现图片的选转
    self.imageView.transform = CGAffineTransformMakeRotation(gr.rotation); } @end
    
    2.6 UIPanGestureRecognizer(连续性手势,拖动) 【Demo6_PanGestureRecognizer】 经常使用属性: //获取移动到的位置在视图坐标系中的绝对位置
    CGPoint location = [gr locationInView:self.view]; //获取移动到的新位置相对于移动动做起始点的坐标的横纵向的偏移
    CGPoint translation = [gr translationInView:self.view]; ViewController.m #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)]; [self.view addGestureRecognizer:panGR]; } -(void)pan:(UIPanGestureRecognizer *)gr{ //获取移动到的位置在视图坐标系中的绝对位置
    CGPoint location = [gr locationInView:self.view]; //获取移动到的新位置相对于移动动做起始点的坐标的横纵向的偏移
    CGPoint translation = [gr translationInView:self.view]; self.myImageView.transform=CGAffineTransformMakeTranslation(translation.x, translation.y);//相对
    NSLog(@"location:(%.2f,%.2f) translation:(%.2f,%.2f)",location.x,location.y,translation.x,translation.y); } @end

3.变形(Transform) 3.1什么是变形 视图发生了位移、缩放、旋转这样的变化叫作变形。 3.2 如何实现变形? 经过修改视图对象的.transform属性完成变化的效果 位移:translation 缩放:scale 旋转:rotation 3.3 transform属性 类型:CGAffineTransform(仿射)类型的结构体 结构体中包含了6个可变的值和3个定值组成的 3 X 3的矩阵,修改了6个数据中的某一个或某几个就能够实现变形,实际上这6个数很难计算,借助于一些系统的API实现数值的改变。 3.4 修改transform属性的API 位移变换:CGAffineTransformMakeTranslation() 相对最原始变化的 CGAffineTransformTranslate() 相对修改后变化的 缩放变换:CGAffineTransformMakeScale() CGAffineTransformScale() 旋转变换:CGAffineTransformMakeRotation() CGAffineTransformRotate() 回到原始状态: CGAffineTransformIdentity 重点注意:变形与自动布局是冲突的,因此在使用变形时,必定要关闭AutoLayout,不关闭的话,产生的效果没法预计。 【Demo7_Transform】 界面建立后,没有作任何变形以前,系统会将每个视图当前的transform记录到一个常量中CGAffineTransformIdentity,当使用Makexxx()方法进行仿射变换,计算新的矩阵,都是基于这个常量进行变形计算的。当使用没有Make的那组方法时,每次计算新的矩阵都是以传入的transform的值做为基准。 3.5 transform属性的初始常量 CGAffineTransformIdentity 如:经过点击按钮实现图片变化 ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } //位移
- (IBAction)translation:(UIButton *)sender { //self.imageView.transform = CGAffineTransformMakeTranslation(0, 350);
    self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, 3, 3); //self.imageView.center = CGPointMake(self.imageView.center.x+2, self.imageView.center.y+2);
} //缩放
- (IBAction)scale:(UIButton *)sender { //self.imageView.transform = CGAffineTransformMakeScale(1.5, 1.5);
    self.imageView.transform = CGAffineTransformScale(self.imageView.transform, 1.2, 1.2); } //旋转
- (IBAction)rotation:(UIButton *)sender { //self.imageView.transform = CGAffineTransformMakeRotation(M_PI_4);
    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, -M_PI_4); } //回到原始位置
- (IBAction)identity:(UIButton *)sender { self.imageView.transform = CGAffineTransformIdentity; } @end4.手势+变形 4.1 使用pan手势实现位移 CGPoint translation = [gr translationInView:self.view]; CGPoint center = CGPointMake(self.imageView.center.x+translation.x, self.imageView.center.y+translation.y); self.imageView.center = center; //将这一次移动的偏移量归零
 [gr setTranslation:CGPointZero inView:self.view]; 4.2 使用pinch手势实现缩放变形 // 实现图片的缩放
     self.imageView.transform = CGAffineTransformScale(self.imageView.transform,gr.scale, gr.scale); gr.scale = 1;// 

    4.3 使用rotation手势实现旋转变形            // 实现图片的旋转
    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, gr.rotation); gr.rotation = 0; 4.4 多手势共存的问题 解决步骤: a。遵照协议 b。设置各个手势的代理 c。实现一个方法 (遵照协议时点开发放寻找粘贴过来便可) - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ return YES; } 5.在storyboard中实现手势 【Demo8_GestureRecognizer_Storyboard】 1.从资源库中拖拽某种类型的手势对象到视图中 2.若是拖拽时就想与某视图关联起来,那么就把手势对象拖到视图中,若是不想关联,那么就拖拽到场景的资源条上 3.选中要关联的视图,按住control,连线到场景的资源条上的手势对象 4. TransformViewController.m #import "TransformViewController.h"

@interface TransformViewController ()<UIGestureRecognizerDelegate> //遵照协议
@property (weak, nonatomic) IBOutlet UIImageView *imageView; @end

@implementation TransformViewController - (void)viewDidLoad { [super viewDidLoad]; //pan手势
    UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)]; [self.view addGestureRecognizer:panGR]; //pinch手势
    UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)]; //设置pinch的代理
    pinchGR.delegate = self; [self.view addGestureRecognizer:pinchGR]; //rotation手势
    UIRotationGestureRecognizer *rotationGR = [[ UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotation:)]; //设置rotation的代理
    rotationGR.delegate = self; [self.view addGestureRecognizer:rotationGR]; } -(void)pan:(UIPanGestureRecognizer *)gr{ //实现图片的位移 //CGPoint location = [gr locationInView:self.view];
    CGPoint translation = [gr translationInView:self.view]; CGPoint center = CGPointMake(self.imageView.center.x+translation.x, self.imageView.center.y+translation.y); self.imageView.center = center; //将这一次移动的偏移量归零
 [gr setTranslation:CGPointZero inView:self.view]; } -(void)pinch:(UIPinchGestureRecognizer *)gr{ // 实现图片的缩放
    self.imageView.transform = CGAffineTransformScale(self.imageView.transform,gr.scale, gr.scale); gr.scale = 1; } -(void)rotation:(UIRotationGestureRecognizer *)gr{ // 实现图片的旋转
    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, gr.rotation); gr.rotation = 0; } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ return YES; } @end  【综合练习】: 图片查看器: 1)使用代码想view中添加一个UIImageView对象,UIImageView的大小和图片大小一致,找一张大图(用大象) 2)使用center属性将ImageView移动到屏幕的中央 3)使用transform属性将imageView缩放到屏幕恰好能显示的下正常图片的内容,且保持宽高比 4)对imageView增长rotation手势,支持图片旋转 5)对imageView增长pinch手势,支持图片的缩放 6)对imageView增长pan手势,支持图片的移动 7)对imageView增长tap手势,床架回到到第3步 注意:手势不要添加到self.view,要添加到图片上,记得打开imageView的用户交互(.userInteractionEnable=YES) 做业: ViewController.m #import "ViewController.h"

@interface ViewController ()<UIGestureRecognizerDelegate>//遵照协议
 @property(nonatomic,strong)UIImageView *imageView; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //建立ImageView
    UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"Elephant.jpg"]]; self.imageView = imageView; //设置初始的状态
 [self loadImageView]; //添加
 [self.view addSubview:imageView]; //开启交互
    imageView.userInteractionEnabled = YES; //设置手势
    UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)]; tapGR.numberOfTapsRequired = 2; [self.imageView addGestureRecognizer:tapGR]; UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)]; pinchGR.delegate = self; [self.imageView addGestureRecognizer:pinchGR]; UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)]; [self.imageView addGestureRecognizer:panGR]; UIRotationGestureRecognizer *rotationGR = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotation:)]; rotationGR.delegate =self; [self.imageView addGestureRecognizer:rotationGR]; } -(void)loadImageView{ //设置中心点
    self.imageView.center = self.view.center; CGFloat scaleX = self.view.bounds.size.width/self.imageView.bounds.size.width; CGFloat scaleY = self.view.bounds.size.height/self.imageView.bounds.size.width; self.imageView.transform = CGAffineTransformMakeScale(MIN(scaleX, scaleY), MIN(scaleX, scaleY)); } //移动
-(void)pan:(UIPanGestureRecognizer *)panGR{ CGPoint translation = [panGR translationInView:self.view]; CGPoint center = CGPointMake(self.imageView.center.x+translation.x, self.imageView.center.y+translation.y); self.imageView.center = center; [panGR setTranslation:CGPointZero inView:self.view]; } //缩放
-(void)pinch:(UIPinchGestureRecognizer *)pinchGR{ self.imageView.transform = CGAffineTransformScale(self.imageView.transform, pinchGR.scale, pinchGR.scale); pinchGR.scale = 1; } //旋转
-(void)rotation:(UIRotationGestureRecognizer *)rotationGR{ self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotationGR.rotation); rotationGR.rotation = 0; } //回到起始点中心点
-(void)tap:(UITapGestureRecognizer *)gr{ [self loadImageView]; } //实现旋转和缩放同时实现的方法
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ return YES; } @end  www.raywenderlich.com 2.根据文档,把一个TableCell实现移动。 长按Cell后,拖到哪里就放在哪里 ==================================================================== 知识点 5、坐标系、触控 1.坐标系(frame、bounds、center、transform) 1.1 frame属性 【Demo1_Frame_Bounds_Center_Transform】 a。什么是frame? 类型:CGRect结构体类型 做用:该视图左顶点在父视图的坐标系中的位置,以及,该视图在父视图中占据的宽和高 b。直接修改了frame属性时,其余属性如何变化? bounds:会被改变 center:会被改变 transform:不会被改变 c。何时使用到frame? 当把一个视图添加到父视图中时,必定要重设定frame属性 1.2 bounds属性 (相对与本身的) a。什么是bounds属性? 类型:CGRect结构体类型 做用:描述的是该视图的坐标系顶点的值,以及该视图自身的大小 b。直接修改了bounds属性时,其余属性如何变化? frame: 会被改变 center:不会被改变 transform:不会被改变 c。何时使用bounds属性? 当须要定位视图时,要读取父视图的大小,那么就是用父视图的bounds 当修改视图内的子视图的位置时,能够修改视图的bounds的坐标起点,从而让子视图的位置发生偏移,实现移动的效果 #import "OtherViewController.h"

@interface OtherViewController () @end

@implementation OtherViewController - (void)viewDidLoad { [super viewDidLoad]; UIView *view1=[[UIView alloc]initWithFrame:CGRectMake(100, 200, 80, 100)]; view1.backgroundColor=[UIColor redColor]; [self.view addSubview:view1]; } - (IBAction)button:(UIButton *)sender { [self.view setBounds:CGRectMake(self.view.bounds.origin.x, self.view.bounds.origin.y+10, self.view.bounds.size.width, self.view.bounds.size.height)]; } @end 点击按钮,图片垂直向上移动 1.3 center属性 a。什么是center属性? 类型:CGPoint结构体类型 做用:描述的是该视图的中心点,在父视图坐标中的位置 b。直接修改了center属性时,其余属性如何变化? frame:会被改变 bounds:不会被改变 transform:不会被改变 c。何时用center? 须要修改视图的位置,也就是位移时,须要修改center 1.4 transform属性 a。什么是transform属性? 类型:CGAffineTransform结构体类型 做用:描述该视图的变形状态 b。直接修改了transform属性时,其余属性如何变化? frame:会 bounds:不会 center:不会 c。结论: 变形前,frame和bounds保持变化的一致性,变形后,frame表明的是在视图中表现出来的外观,因此会随着变形而记录不一样的外观状态,但bounds不是用来表现的,只是记录大小的,因此不会改变,bounds的坐标系也不会改变 ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self print]; } //直接修改frame
- (IBAction)changFrame:(UIButton *)sender { CGRect frame=self.imageView.frame; frame.origin.x+=4; frame.origin.y+=4; frame.size.width+=4; frame.size.height+=4; self.imageView.frame=frame; [self print]; } //直接修改bounds
- (IBAction)changeBounds:(UIButton *)sender { CGRect bounds=self.imageView.bounds; //bounds.origin.x+=4; // bounds.origin.y+=4;
    bounds.size.width+=4; bounds.size.height+=4; self.imageView.bounds=bounds; [self print]; } //直接修改center
- (IBAction)changeCenter:(UIButton *)sender { CGPoint center=self.imageView.center; center.x+=4; center.y+=4; self.imageView.center=center; [self print]; } //直接修改transform
- (IBAction)changeTransform:(UIButton *)sender { self.imageView.transform=CGAffineTransformTranslate(self.imageView.transform, 4, 4); self.imageView.transform=CGAffineTransformScale(self.imageView.transform, 1.3, 1.3); self.imageView.transform=CGAffineTransformRotate(self.imageView.transform, M_1_PI); [self print]; } -(void)print{ NSLog(@"\nframe:%@\nbounds:%@\ncenter:%@\ntransform:%@", NSStringFromCGRect(self.imageView.frame), NSStringFromCGRect(self.imageView.bounds), NSStringFromCGPoint(self.imageView.center), NSStringFromCGAffineTransform(self.imageView.transform)); } @end 点击了bounds按钮 原始: frame:{{91, 33}, {112, 100}} bounds:{{0, 0}, {112, 100}} center:{147, 83} transform:[1, 0, 0, 1, 0, 0] 点击后: frame:{{89, 31}, {116, 104}} bounds:{{0, 0}, {116, 104}} center:{147, 83} transform:[1, 0, 0, 1, 0, 0] 2.触控(UITouch) 2.1 是什么? 是一个UITouch类型的对象,当用户touch视图时,会自动产生UITouch对象 2.2 如何获取Touch 须要自定义视图类,覆盖类中的指定的方法,在方法中才能获取到这个Touch对象 2.3 有什么用? 能够跟踪用户在视图上手指移动的轨迹,判断用户的意图,以此进行绘图、涂鸦、手写等操做 2.4 怎么用? step1:自定义一个视图类 step2:重写类中的方法便可 touchesBegan:withEvent://手指接触视图时调用
                        touchesMoved:withEvent://手指在视图上移动时调用
                        touchesEnded:withEvent://手指离开视图时调用
 注意:手势是对触控的一个封装 【Demo3_UITouch】 MyView.h(本身建立的类,关联到VC) #import "MyView.h"
@implementation MyView //手指接触调用
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch*touch=[touches anyObject]; CGPoint location=[touch locationInView:self]; NSLog(@"手指接触屏幕:(%.2f,%.2f)",location.x,location.y); } //手指在视图移动时
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch*touch=[touches anyObject]; CGPoint location=[touch locationInView:self]; NSLog(@"手指在视图上移动:(%.2f,%.2f)",location.x,location.y); } //离开时
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"手指离开视图"); } @end 手指接触屏幕:(147.00,87.00) 手指在视图上移动:(146.50,89.00) 手指在视图上移动:(148.50,92.00) 手指离开视图 练习:简易画板 【Demo4_Touch_Paint】 PaintView.h PaintView.m #import "PaintView.h"

@interface PaintView () //记录全部路径的可变数组
@property(nonatomic,strong)NSMutableArray *paths; @end

@implementation PaintView - (NSMutableArray *)paths{ if (!_paths) { _paths = [NSMutableArray array]; } return _paths; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ //获取UITouch对象
    UITouch *touch = [touches anyObject]; CGPoint startPoint = [touch locationInView:self]; // 建立路径
    UIBezierPath *path = [UIBezierPath bezierPath]; [path setLineWidth:3]; [path moveToPoint:startPoint]; // 将路径对象记录到数组属性中
 [self.paths addObject:path]; } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *touch = [touches anyObject]; CGPoint currentPoint = [touch locationInView:self]; //将刚刚建立的路径添加一个直线到该点 //从数组中取出最后一个元素,就是刚刚手指落下时 //建立的路径
    UIBezierPath *currentPath = [self.paths lastObject]; [currentPath addLineToPoint:currentPoint]; //重绘
 [self setNeedsDisplay]; } - (void)drawRect:(CGRect)rect { //绘制全部路径
    for (UIBezierPath *path in self.paths) { [path stroke]; } } @end  做业: 1. 作一个界面上画矩形的效果 按下手指后开始画,拖动时大小变化,松手后定在屏幕上,支持绘制多个矩形 2. 在做业1的基础上,支持选择绘制的颜色,支持线条的粗细设置 3. 在做业1或2的基础上,增长橡皮功能 4. 支持各类形状—矩形,圆角矩形,椭圆。。。。 ======================================================================================================= 知识点 6、布局 1.布局 (Layout)控制器中的view 1.1 什么是布局? 是指在一个视图中如何摆放它的子视图(安排子视图的位置和大小) 1.2 为何要布局? 屏幕的尺寸会常常发生变化或者随着设备不一样,屏幕尺寸也会不一样,只要屏幕大小发生了变化,坐标系也会随之变化,因而变化前设置的frame在新的坐标系中定位就会与期待的不符,因此就须要在屏幕发生变化时从新布局指定frame 【Demo5_Layout】 1.3 可能致使屏幕大小发生变化的缘由 a。设备不一样(3.5寸 4存。。。。) b。屏幕方向不一样 c。状态栏 隐藏 特殊的状态栏:来电时,绿色状态栏 录音时,红色状态栏 开启我的热点,蓝色状态栏 d。各类Bar NavigationBar: 44/32 若是设置了prompt,bar会更高 TabBar:49个点高 ToolBar:44/32 个点 iOS7中,导航栏挤占了状态栏,高度是64/52 e。键盘 弹出时挤占屏幕,高度不肯定,由于中英文键盘的高度不一样 1.4 如何布局 方法一:纯代码布局,古老的方法 理念:当屏幕发生变化时,自动执行一段咱们写好的代码,代码中从新计算了视图的frame,从而达到在新坐标系下从新定位的目的 特色:功能强大,很是繁琐 方法二:Auto Resizing 之前的一种自动布局技巧 理念:记录视图与父视图的边缘为可调整或固定值,而后屏幕发生变化时,依据这段相对的距离,从新布局视图 特色:操做简单,功能有限 方法三:Auto Layout 最新的自动布局方法 理念:将视图与视图之间的位置以及视图自身的大小,用多个约束来记录,当屏幕发生变化时,系统根据定好的约束,自动计算知足该约束状况下的新的坐标值,而后调整位置 特色:简单易用 注意:以上的布局方式,选择其一使用。 4. 纯代码布局 4.1 理念:在屏幕大小发生变化时,经过代码的方式改变视图的frame 4.2 重写控制器中方法:viewDidLayoutSubviews:便可 该方法,在屏幕发生变化时,由系统自动调用,因此,改变frame的代码写在这个方法中就会被自动执行了。 注意:使用纯代码布局时,必定要关闭AutoLayout,不然代码可能会无效 【Demo5_Layout】 【练习】 1.两个等宽的按钮,高40,有背景色 ——————————————— |               20                    20             |
            |-20-[button1]-10-[button2]-20-|
    2.在1的基础上,加一个大小会变化的ImagView(内有图片) imageView离屏幕上、下、左、右保持70,502020
    3.在2的基础上,增长三个按钮,大小是20X20,永远排列在屏幕的右下角 【b1】-10-【b2】-10-【b3】-20-|
                             20                20                20          | ———————————————| b1,2,3离下边缘都是20个点 时间:半个小时 补充: 关掉AutoLayout之后,drawRect方法中针对视图绘制的图形在屏幕旋转时会被拉伸,解决该问题的话,须要设置视图的“contentMode”设置为“redraw”便可 解决方法:设置视图的的contentMode为redraw便可 ViewController.h ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIButton *button1; @property (weak, nonatomic) IBOutlet UIButton *button2; @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property (weak, nonatomic) IBOutlet UIButton *b1; @property (weak, nonatomic) IBOutlet UIButton *b2; @property (weak, nonatomic) IBOutlet UIButton *b3; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } -(void)viewDidLayoutSubviews{ [super viewDidLayoutSubviews]; CGFloat buttonWidth = (self.view.bounds.size.width - 20 - 20 - 10)/2; CGRect frame = CGRectMake(20, 20, buttonWidth, 40); self.button1.frame = frame; frame.origin.x += buttonWidth + 10; self.button2.frame = frame; frame.size = CGSizeMake(self.view.bounds.size.width-20-20, self.view.bounds.size.height-70-50); frame.origin = CGPointMake(20, 70); self.imageView.frame = frame; frame.size = CGSizeMake(20, 20); frame.origin = CGPointMake(self.view.bounds.size.width-20-20, self.view.bounds.size.height-20-20); self.b3.frame =frame; frame.origin.x -= (10+20); self.b2.frame = frame; frame.origin.x -= (10+20); self.b1.frame = frame; } @end 故事板中的界面随意布局就好,作一个控件的建立就行了 2.UIView对内部的子视图的布局(典型应用:TableViewCell对内部子视图的布局) 1.1 如何实现? step1:自定义视图,继承自UIView step2:重写自定义视图的方法 a。 viewWillLayoutSubViews b。 layoutSubViews c。 viewDidLayoutSubView 方法执行的顺序:a->b->c 通常重写 layoutSubViews方法便可。 练习:音乐列表 【Demo1_TableViewCell_Layout】 Mondel TRMusic.h #import <Foundation/Foundation.h>

@interface TRMusic : NSObject @property (nonatomic, copy) NSString * name;//歌曲名
@property (nonatomic, copy) NSString * album;//专辑
@property (nonatomic, copy) NSString * artist;//艺术家
 @property (nonatomic) NSTimeInterval duration;//时长
 @property (nonatomic) BOOL highQuality;//高品质
@property (nonatomic) BOOL downloaded;//下载

@end TRMusic.m #import "TRMusic.h"

@implementation TRMusic @end TRMusicGroup.h #import <Foundation/Foundation.h>
#import "TRMusic.h" typedef NS_ENUM(NSInteger, TRMusicGroupState) { TRMusicGroupStateNormal, //音乐组的状态
 TRMusicGroupStateDownloading, TRMusicGroupStateDownloaded }; @interface TRMusicGroup : NSObject @property (nonatomic, copy) NSString * name;//组名字
 @property (nonatomic, strong) NSArray * musics;//多个音乐
 @property (nonatomic) TRMusicGroupState state;//状态

+ (NSArray *) fakeData; @end TRMusicGroup.m #import "TRMusicGroup.h"

@implementation TRMusicGroup + (NSArray *) fakeData { NSMutableArray * musics = nil; TRMusic * music = nil; musics = [NSMutableArray array]; music = [[TRMusic alloc] init]; music.name = @"Burn"; music.album = @"Burn - Single"; music.artist = @"Ellie Goulding"; music.duration = [self durationWithMinutes:3 andSeconds:51]; music.downloaded = YES; music.highQuality = NO; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"Summertime Sadness (Cedric Gervais Remix)"; music.album = @"Summertime Sadness (Cedric Gervais Remix) - Single"; music.artist = @"Lana Del Rey"; music.duration = [self durationWithMinutes:6 andSeconds:52]; music.downloaded = YES; music.highQuality = YES; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"Spectrum"; music.album = @"Clarity"; music.artist = @"Zedd"; music.duration = [self durationWithMinutes:4 andSeconds:3]; music.downloaded = YES; music.highQuality = YES; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"It's Time"; music.album = @"It’s Time"; music.artist = @"Imagine Dragons"; music.duration = [self durationWithMinutes:4 andSeconds:0]; music.downloaded = NO; music.highQuality = YES; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"Dancing in The Moonlight"; music.album = @"Dancing In The Moonlight: The Best Of Toploader"; music.artist = @"Toploader"; music.duration = [self durationWithMinutes:3 andSeconds:53]; music.downloaded = YES; music.highQuality = YES; [musics addObject:music]; TRMusicGroup * g1 = [[TRMusicGroup alloc] init]; g1.name = @"国外单曲"; g1.musics = [musics copy]; g1.state = TRMusicGroupStateDownloaded; musics = [NSMutableArray array]; music = [[TRMusic alloc] init]; music.name = @"你有本事抢男人"; music.album = @"好大的胆子"; music.artist = @"雪姨"; music.duration = [self durationWithMinutes:3 andSeconds:18]; music.downloaded = NO; music.highQuality = NO; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"喂鸡"; music.album = @"六十年代生人"; music.artist = @"刘欢"; music.duration = [self durationWithMinutes:3 andSeconds:41]; music.downloaded = NO; music.highQuality = YES; [musics addObject:music]; music = [[TRMusic alloc] init]; music.name = @"忐忑"; music.album = @"自由鸟"; music.artist = @"龚琳娜"; music.duration = [self durationWithMinutes:4 andSeconds:03]; music.downloaded = NO; music.highQuality = YES; [musics addObject:music]; TRMusicGroup * g2 = [[TRMusicGroup alloc] init]; g2.name = @"国内神曲"; g2.musics = [musics copy]; g2.state = TRMusicGroupStateNormal; TRMusicGroup * g3 = [[TRMusicGroup alloc] init]; g3.name = @"Calvin Harris 专辑"; g3.musics = @[]; g3.state = TRMusicGroupStateNormal; TRMusicGroup * g4 = [[TRMusicGroup alloc] init]; g4.name = @"Ellie Gounding 专辑"; g4.musics = @[]; g4.state = TRMusicGroupStateNormal; return @[g1, g2, g3, g4]; } + (NSTimeInterval) durationWithMinutes:(int)minutes andSeconds:(int)seconds { return minutes * 60 + seconds; } @end MusilcTableViewController.h #import <UIKit/UIKit.h>
#import "TRMusicGroup.h"
@interface MusilcTableViewController : UITableViewController @property(nonatomic,strong)TRMusicGroup*musicGroup; @end MusilcTableViewController.m #import "MusilcTableViewController.h"
#import "MusicTableViewCell.h"
#import "TRMusic.h"
@interface MusilcTableViewController () @end

@implementation MusilcTableViewController - (void)viewDidLoad { [super viewDidLoad]; } //获取列表内容
-(TRMusicGroup *)musicGroup{ if (!_musicGroup) { _musicGroup=[TRMusicGroup fakeData][0]; } return _musicGroup; } #pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.musicGroup.musics.count; } /**/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { MusicTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MusicCell" forIndexPath:indexPath]; //找出音乐,获取数据
    TRMusic* music=self.musicGroup.musics[indexPath.row]; //将音乐赋给cell
    cell.music=music; return cell; } @end MusicTableViewCell.h #import <UIKit/UIKit.h>
#import "TRMusic.h"

@interface MusicTableViewCell : UITableViewCell @property(nonatomic,strong)TRMusic*music; @end MusicTableViewCell.m #import "MusicTableViewCell.h"
@interface MusicTableViewCell () //扩展属性
@property (weak, nonatomic) IBOutlet UILabel *nameLabel; @property (weak, nonatomic) IBOutlet UILabel *durationLabel; @property (weak, nonatomic) IBOutlet UILabel *artistLabel; @property (weak, nonatomic) IBOutlet UIImageView *downloadedImageView; @property (weak, nonatomic) IBOutlet UIImageView *highQualityImageView; @end

@implementation MusicTableViewCell //重写set方法
-(void)setMusic:(TRMusic *)music{ _music = music; //将music的各个属性放到对应的控件上
    self.nameLabel.text = self.music.name; self.durationLabel.text=[NSString stringWithFormat:@"%d:%02d",(int)self.music.duration/60,(int)self.music.duration%60]; self.artistLabel.text=[[self.music.artist stringByAppendingString:@"-"]stringByAppendingString:self.music.album]; self.downloadedImageView.hidden = !self.music.downloaded; self.highQualityImageView.hidden = !self.music.highQuality; } //重写 cell对本身内部子视图的布局
-(void)layoutSubviews{ [super layoutSubviews]; CGFloat x=self.downloadedImageView.frame.origin.x; if (self.music.downloaded) { x+=20; } if (self.music.highQuality) { CGRect rect=self.highQualityImageView.frame; rect.origin.x=x; self.highQualityImageView.frame=rect; x+=20; } CGRect fram=self.artistLabel.frame; fram.origin.x=x; self.artistLabel.frame=fram; } @end1.2. 布局对状态栏和各类Bar的处理 使用属性:topLayoutGuide.length//屏幕上方当前被占据的区域的长度 
                         bottomLayoutGuide.length//屏幕下方当前被占据的长度
 【Demo2_Layout_Bar】 #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIButton *button; @property (weak, nonatomic) IBOutlet UILabel *label; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (void)viewDidLayoutSubviews{ CGRect frame = self.button.frame; frame.origin.x = self.view.bounds.size.width-20-frame.size.width; frame.origin.y = self.topLayoutGuide.length+10; self.button.frame = frame; frame = self.label.frame; frame.origin.x = self.view.bounds.size.width -20 - frame.size.width; frame.origin.y = self.view.bounds.size.height - self.bottomLayoutGuide.length - frame.size.height; self.label.frame = frame; } //点击屏幕隐藏工具栏
- (IBAction)changeBar:(UITapGestureRecognizer *)sender { [self.navigationController setNavigationBarHidden:!self.navigationController.navigationBarHidden animated:YES]; [self.navigationController setToolbarHidden:!self.navigationController.toolbarHidden animated:YES]; } - (BOOL)prefersStatusBarHidden{ return YES; } @end3. 手动设置Autoresizing 布局 3.1 是什么? 是旧版本(iOS5以前)的自动布局奇数。操做简单,API简单,功能也简单,有局限性,好久之前叫 struts/spring(架构/弹性)技术 3.2 核心理念 当界面大小发生变化时,根据变化的比例,对子视图进行同比例的变化 3.3 怎么样 step1:关闭AutoLayout step2:选中须要布局的子视图 step3:打开检查器5 step4:点亮须要的红线 外框(4个)红线负责子视图到父视图的边缘 内框(2个)红线负责子视图内部是否能够拉伸 【Demo3_Autoresizing】 4.编写代码实现Autoresizing 布局 Autoresizing和代码布局能够同时使用,用代码补齐Autoresizing的不足 button.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleBottomMargin; 代码设置时,规则描述与在检查器中描述相反,只须要设置可变的边距 如: - (void)viewDidLoad { [super viewDidLoad]; /**/ UIButton* button=[UIButton buttonWithType:UIButtonTypeSystem]; [button setTitle:@"button1" forState:UIControlStateNormal]; [button setBackgroundColor:[UIColor redColor]]; button.frame=CGRectMake(self.view.bounds.size.width-120, 20, 100, 40); [self.view addSubview:button]; //点亮红线
    button.autoresizingMask=UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleBottomMargin; } 5.Autolayout(自动布局) 5.1 是什么? 是从iOS6开始的一个新的布局技术,功能强大,操做复杂。从xcode5开始,慢慢好用了。在xcode6中,功能更强大了。 核心理念:使用约束(constraint)来描述控件在视图中的位置,当屏幕大小发生变化时,系统会根据你设定的约束自动计算出frame的值,而后将该值赋给控件,实现控件的排布 5.2 使用故事板为控件添加约束 【Demo4_AutoLayout】 5.3 操做要点 a。选中控件,分析6点,上下左右及控件的宽高须要哪些约束才能肯定 b。约束的添加能够经过屏幕下方的选项,或者是,选中控件后,按住control,连线到屏幕边缘或其余视图 c。能够添加的约束有:对齐方式(与中心点对齐或与其余控件对齐)、与边缘或其余视图的间距(前导间距和尾部边距)、视图的宽高是给定值仍是以其余视图作参照标准 d。添加约束后,正确的结果出现时,屏幕中只有蓝色的线,存在红色虚线框框时,表明视图占据的区域,有橘色线条时,表明当前摆放位置与定义的位置有距离,能够经过底部的第三个选项菜单,选择更新某个视图的frame或更新全部视图的frame e。选中一个视图,查看第5个检查器能够看到该视图已经添加了的约束,能够选中约束修改约束的内容 f。选中一个视图,经过查看场景的文档结构图,观察该场景下的约束是否有错误或警告,若是有,能够点击该场景的右上角的红色点点,进入说明界面,红色的提示为一场,必须修改成正确,方可表明系统承认约束,能够进行布局,橘色的提示,通常是实际位置与约束位置有误差,只要更新frame,就可让橘色的警告消失 6.Auto Layout 代码建立约束 1.1 何时用? 当子视图对象时代码建立时,而且须要给子视图布局时,只能用代码来进行自动布局 1.2 如何添加约束? step1:建立约束对象 NSLayoutConstraint (API) step2:将约束添加到父视图 1.3 建立约束对象 方法一:使用万能公式 + (instancetype)constraintWithItem:(id)view1
                 attribute:(NSLayoutAttribute)attr1
                 relatedBy:(NSLayoutRelation)relation
                        toItem:(id)view2
                 attribute:(NSLayoutAttribute)attr2
               multiplier:(CGFloat)multiplier
                  constant:(CGFloat)c 公式:view1.attr1<relation>view2.attr2*multiplier +contant 如: button.left = self.view.left*0 + 20 button.right = self.view.width*1 + (-20) 注意:translateAutoresizingToConstraints这个属性默认是YES,这个属性表明:将视图默认自带的Auto resizing特性是否自动转换为对应的约束。既然使用代码来建立约束,那么就不要让系统自带的转换过来的约束影响添加的自定义约束,因此该属性要设置为NO,为了保证效果,能够将视图以及视图的父视图的该属性都设置为NO //关闭视图自身的翻译
    button1.translatesAutoresizingMaskIntoConstraints = NO; self.view.translatesAutoresizingMaskIntoConstraints = NO; 【Demo1_Autolayou_Code】 如: - (void)viewDidLoad { [super viewDidLoad]; UIButton *button1 = [UIButton buttonWithType:UIButtonTypeSystem]; [button1 setTitle:@"button1" forState:UIControlStateNormal]; button1.backgroundColor = [UIColor lightGrayColor]; [self.view addSubview:button1]; //关闭视图自身的翻译
    button1.translatesAutoresizingMaskIntoConstraints = NO; self.view.translatesAutoresizingMaskIntoConstraints = NO; //建立约束
    NSLayoutConstraint *c1 = [NSLayoutConstraint constraintWithItem:button1 attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:0 constant:20]; [self.view addConstraint:c1]; NSLayoutConstraint *c2 = [NSLayoutConstraint constraintWithItem:button1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:0 constant:20]; [self.view addConstraint:c2]; //
    NSLayoutConstraint *c3 = [NSLayoutConstraint constraintWithItem:button1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:0 constant:150]; [self.view addConstraint:c3]; } 方法二:一次建立多个约束,使用VFL(Visual Format Language) + (NSArray *)constraintsWithVisualFormat:(NSString *)format
            options:(NSLayoutFormatOptions)opts 参数2:对齐方式
            metrics:(NSDictionary *)metrics
                   views:(NSDictionary *)views 参数4:建立添加的对象 特色:功能强大 【Demo2_Autolayout_Code_VFL】 1.4 VFL(Visual Format Language) a。是什么? 一个字符串,具备必定的格式,表明一些约束的含义 b。如何写VFL字符串? | 表明父视图的边 V:| 表明垂直方向的父视图的上边 [ ] 表明一个子视图(或控件) ( ) 表明一个条件(== 、 >=、<=)==能够省略 - 表明间距,默认的8个点 -xxx- 表明间距是多少 [button2(button1)] :button1与button2的高度相同 如: |-20-[button1]-10-[button2(button1)]-10-[button3(button1)]-20-| V:|-20-[button1] c。metrics参数 (用于替换参数3) 用于指定VFL字符串中能够替换的值,是一个字典类型 如:NSDictionary *metrics = @{@"left":@20,@"space":@10,@"right":@20}; d。NSDictionaryOfVariableBinding()函数 (用于替换参数4) NSDictionary *dictionary = NSDictionaryOfVariableBindings(b1,b2,b3); 生成的字典以下: @{@"b1":b1,@"b2":b2,@"b3":b3} 如: #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //需求:屏幕上方 添加三个等宽的按钮
    UIButton *b1 = [UIButton buttonWithType:UIButtonTypeSystem]; [b1 setTitle:@"button1" forState:UIControlStateNormal]; b1.backgroundColor = [UIColor lightGrayColor]; [self.view addSubview:b1]; UIButton *b2 = [UIButton buttonWithType:UIButtonTypeSystem]; [b2 setTitle:@"button2" forState:UIControlStateNormal]; b2.backgroundColor = [UIColor lightGrayColor]; [self.view addSubview:b2]; UIButton *b3 = [UIButton buttonWithType:UIButtonTypeSystem]; [b3 setTitle:@"button3" forState:UIControlStateNormal]; b3.backgroundColor = [UIColor lightGrayColor]; [self.view addSubview:b3]; //1.添加约束的第一步:关闭自动翻译
    b1.translatesAutoresizingMaskIntoConstraints = NO; b2.translatesAutoresizingMaskIntoConstraints = NO; b3.translatesAutoresizingMaskIntoConstraints = NO; self.view.translatesAutoresizingMaskIntoConstraints = NO; //下面的函数会将传入的多个引用构建成以下的字典形式: //@{@"b1":b1,@"b2":b2,@"b3":b3}
    NSDictionary *dictionary = NSDictionaryOfVariableBindings(b1,b2,b3); NSDictionary *metrics = @{@"left":@20,@"space":@10,@"right":@20}; //2.第二步:建立约束 //2.1准备一个VFL //NSString*hVFL=@"|-20-[button1]-10-[button2(==button1)]-10-[button3(==button1)]-20-|";
     NSString *hVFL = @"|-left-[b1]-space-[b2(b1)]-space-[b3(b1)]-right-|"; //2.2建立约束
    NSArray *cs = [NSLayoutConstraint constraintsWithVisualFormat:hVFL options:NSLayoutFormatAlignAllCenterY metrics:metrics views:dictionary]; //3.将约束添加到父视图中
 [self.view addConstraints:cs]; NSString *vVFL = @"V:|-left-[button1]"; cs = [NSLayoutConstraint constraintsWithVisualFormat:vVFL options:0 metrics:metrics views:@{@"button1":b1}]; [self.view addConstraints:cs]; } @end======================================================================= 知识点 7、动画 1.动画 (Animation) 1.1 是什么? “帧动画”:一帧 是一张静态的图片,通常状况下,1秒钟达到24,5帧的时候,人眼就分辨不出图片的切换过程,就有连续的效果产生 帧率(FPS)Frame Per Second 1.2 iOS中的动画 UIImage 类,自带一些方法,能够作简单动画 NSTimer 类,间隔指定时间,产生切换效果 UIView类 原本提供了动画的功能 底层的Core Animation 提供了动画的支持 在iOS7中增长一些动画功能: UIKit Dynamic 动力 Motion Effects 特效 Sprite Kit (2D引擎) 2. UIImage动画 【Demo3_UIImage_Animation】 //duration:播放一组图片用的时间
    UIImage *image = [UIImage animatedImageNamed:@"ship-anim" duration:1*5/30]; 1秒播放30帧,播放一张图片须要1/30,5张照片 self.imageView.image = image; 3. NSTimer 动画 4.1 是什么? 一个计时器类,用于定时向指定对象发消息 4.2 如何使用? 【Demo4_NSTimer】 1.//建立计时器 //使用schedule。。开头的方法时,定时器建立完毕就会启动
    self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(doSomething:) userInfo:nil repeats:YES]; //使用timerWith。。。开头的方法建立timer //定时器不会在建立完毕后启动 //须要使用代码将定时器添加到时间循环中才能启动
    self.timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(doSomething:) userInfo:nil repeats:YES]; 2.//启动定时器
 [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode]; 3.//关闭定时器
 [self.timer invalidate]; 练习:【Demo5_NSTimer_Alpha】 使用NSTimer作一个图片淡入的效果(经过修改alpha透明度值来完成) #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)NSTimer *timer; @property(nonatomic)NSInteger count; @end

@implementation ViewController #define FPS 30.0
#define DURATION 5.0

- (void)viewDidLoad { [super viewDidLoad]; self.imageView.alpha = 0; self.timer = [NSTimer scheduledTimerWithTimeInterval:1/FPS target:self selector:@selector(changeAlpha:) userInfo:nil repeats:YES]; } //匀速动画的公式 //当前值 = 开始值+当前帧数*(结束值-开始值)/(帧率*动画时长)
-(void)changeAlpha:(NSTimer *)timer{ //count表明当前帧数
    self.count++; self.imageView.alpha = 0 + self.count*(1-0)/(FPS*DURATION); if (self.count>=FPS*DURATION) { [timer invalidate]; } } @end

    4.3 匀速动画 公式:当前值= 开始值+当前帧数*(结束值-开始值)/(帧率*动画时长) 这个值能够是:center transform frame alpha 【Demo6_NSTimer_Animation】 4.4 变速动画 由快到慢、由慢到快、由慢到快再到慢 公式: 当前值 = 上一次的值+(目标值-上一次值)*渐进因子 渐进因子根据状况调节 【Demo7_NSTimer_Animation】 #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *airCraft; @end

@implementation ViewController #define FPS 30.0

- (void)viewDidLoad { [super viewDidLoad]; } - (IBAction)start:(id)sender { [NSTimer scheduledTimerWithTimeInterval:1/FPS target:self selector:@selector(move:) userInfo:nil repeats:YES]; } //当前值=上一次的值+(目标值-上一次的值)*渐进因子 /* 400 + (100 - 400)*0.1 = 370 30p 370 + (100 - 370)*0.1 = 343 27p 343 + (100 - 343)*0.1 = 319.7 24.3 */
-(void)move:(NSTimer *)timer{ CGPoint center = self.airCraft.center; center.y = center.y+(50-center.y)*0.05; self.airCraft.center = center; if (center.y<=51.0) { [timer invalidate];//结束
 } } @end

5. UIView 动画:真正的动画,有专门的API 5.1 是什么 有UIKit专门制做动画的API,这些API的底层对Core Animation的封装,能够轻松实现动画,不用再计算每一帧的值来实现动画的效果 5.2 制做动画的步骤 step1:设置须要动画的视图的初始值 step2:给UIView类发消息,告诉UIView类须要什么样的动画 step3:将动画结束的状态(属性值),即变化的结果,写入到一个Bloack中 [UIView animateWithDuration:2.0 delay:0 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse animations:^{ //设置动画结束时,被动画的那个视图的结束状态
        self.airCraft.center = endCenter; self.airCraft.transform = transform; } completion:nil]; 【Demo8_UIView_Animation】 5.3 动画的高级选项 先慢后快再慢 UIViewAnimationOptionCurveEaseInOut 愈来愈快 UIViewAnimationOptionCurveEaseIn 愈来愈慢 UIViewAnimationOptionCurveEaseOut 匀速 UIViewAnimationOptionCurveLinear 动画重复 UIViewAnimationOptionRepeat 反着执行动画,要配合Repeat选项 UIViewAnimationOptionAutoreverse 要求:启动后,从屏幕左边弹出label,从屏幕下边弹出image,而后点击按钮,飞机实现旋转飞行,并重复飞行 #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *airCraft; @property (weak, nonatomic) IBOutlet UILabel *welcomeLabel; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; CGRect endFrame = self.welcomeLabel.frame; CGRect startFrame = endFrame; startFrame.origin.x = -startFrame.size.width; //1.设置须要动画的视图的初始属性
    self.welcomeLabel.frame = startFrame; self.welcomeLabel.alpha = 0.1; //2.给UIView发消息
    [UIView animateWithDuration:2.0 animations:^{ self.welcomeLabel.frame = endFrame; self.welcomeLabel.alpha = 1.0; }]; endFrame = self.airCraft.frame; startFrame = endFrame; startFrame.origin.y = self.view.bounds.size.height; self.airCraft.frame = startFrame; [UIView animateWithDuration:2.0 animations:^{ self.airCraft.frame = endFrame; }]; } - (IBAction)start:(id)sender { //这是当前中心点
    CGPoint endCenter = self.airCraft.center; //计算结束位置的y值
    endCenter.y -=300; //旋转
    CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI); [UIView animateWithDuration:2.0 delay:0 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse animations:^{ //设置动画结束时,被动画的那个视图的结束状态
        self.airCraft.center = endCenter; self.airCraft.transform = transform; } completion:nil]; } @end  做业 1.飞机放到屏幕上之后,点哪,飞哪儿 2.作一个购物车的动画 在屏幕的左上角有一个UIImageView,图片是一个商品。 当用户点击此商品时,商品会从上面掉下来,落入到下面的购物车中, 注意:商品掉下来时,屏幕左上角的图片不会消失 例: #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController #define FPS 30.0
#define MAX_SIZE 10
#define MAX_DURATION 10


- (void)viewDidLoad { [super viewDidLoad]; //启动定时器,建立雪花
    [NSTimer scheduledTimerWithTimeInterval:1/FPS target:self selector:@selector(animate:) userInfo:nil repeats:YES]; } -(void)animate:(NSTimer *)timer{ //1.建立一个雪花
    UIImageView *snow = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"snow.png"]]; int viewWidth = self.view.bounds.size.width; int viewHeight = self.view.bounds.size.height; CGFloat size = MAX_SIZE+arc4random()%MAX_SIZE; snow.frame = CGRectMake(arc4random()%viewWidth, -20, size, size); [self.view addSubview:snow]; //2.建立动画
    [UIView animateWithDuration:arc4random()%MAX_DURATION+2  delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ //3. 设置动画结束时雪花的位置信息
        int offset = arc4random()%100 - 50; snow.center = CGPointMake(snow.center.x+offset, viewHeight-30); }completion:^(BOOL finished) { //4.落地动画结束时,开始融雪
        [UIView animateWithDuration:arc4random()%MAX_DURATION delay:0 options:UIViewAnimationOptionCurveEaseIn  animations:^{ snow.alpha = 0; } completion:^(BOOL finished) { //5.融雪动画结束时,将图片移出父视图
 [snow removeFromSuperview]; }]; }]; } ====================================================================== 知识点 7、Core Animation 1.Core Animation 1.1是什么 是一个图形渲染和动画的底层框架,用于iOS和Mac OS X 1.2 能干什么 1)能够提供更多更强大的图形渲染(显示)效果 2)能够提供专业级的动画效果 3)是高层图形技术的基础 1.3 如何使用Core Animation (内容较多,很庞大,只讲经常使用的) 经过CALayer类,直接对一个视图(UIView及子类)的 Core Animation层进行一些设置,达到须要的效果 1.4 如何得到CALayer这一层呢? 任何UIView及其子类都有一个属性叫layer UIView CALayer .layer .frame .frame .transform .transform3D .autoresizing .autoresizing .addSubView: .addSubLayer: 【Demo1_CoreAnimation】 #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; CALayer *layer = self.view.layer; layer.backgroundColor = [[UIColor orangeColor] CGColor]; layer.cornerRadius = 30.0; self.imageView.layer.cornerRadius = 10.0; //打开遮罩
    self.imageView.layer.masksToBounds = YES; // 加子层
    CALayer *subLayer = [CALayer layer]; subLayer.backgroundColor = [[UIColor purpleColor]CGColor]; subLayer.frame = CGRectMake(30, 200, 100, 120); subLayer.shadowColor = [[UIColor greenColor]CGColor]; subLayer.shadowOffset = CGSizeMake(2, 2); subLayer.shadowRadius = 5.0; subLayer.shadowOpacity = 0.8;阴影透明度,设置它阴影才会显示 subLayer.cornerRadius = 10.0; [layer addSublayer:subLayer]; //有内容的子层
    CALayer *imageLayer = [CALayer new]; imageLayer.frame = CGRectMake(180, 250, 100, 120); imageLayer.contents = (id)[UIImage imageNamed:@"d.jpg"].CGImage;//添加图片
    imageLayer.cornerRadius = 10; imageLayer.masksToBounds = YES; [layer addSublayer:imageLayer]; } @end1.5 CAAnimation 一个抽象的动画类型,不少时候不关心这个父类,而是使用它的子类来实现动画 1) CAKeyframeAnimation 关键帧动画 能够根据指定的路径进行动画 实现步骤: step1:建立关键帧动画 使用animationWithKeyPath:方法建立,同时,最后一个字符串参数必须是如下几种选择: position transform opacity step2:设置动画属性 step3:将动画添加到视图的layer层上 2)CABasicAnimation能够实现缩放,旋转,透明度等动画 特色:设置动画属性主要为两个:fromValue 和 toValue 例:点击按钮,图片按曲线移动,而且移动的时候会缩小,而且会消失 #import "AnimationViewController.h"

@interface AnimationViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end

@implementation AnimationViewController - (void)viewDidLoad { [super viewDidLoad]; } - (IBAction)start:(id)sender { UIBezierPath *path = [UIBezierPath bezierPath]; [self createPath:path]; // 建立关键帧动画
    CAKeyframeAnimation *moveAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; // 设置相关的属性
    moveAnimation.path = path.CGPath; //moveAnimation.duration = 2.0; //[self.imageView.layer addAnimation:moveAnimation forKey:nil]; //建立缩放动画
    CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform"]; scaleAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; scaleAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1, 0.1, 0.1)]; //scaleAnimation.duration = 2.0; //[self.imageView.layer addAnimation:scaleAnimation forKey:nil]; //透明度动画
    CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; alphaAnimation.fromValue = @1.0; alphaAnimation.toValue = @0.0; //alphaAnimation.duration = 2.0; //[self.imageView.layer addAnimation:alphaAnimation forKey:nil]; //建立动画组,将全部动画对象添加到组中 //针对组设置的动画属性,会被应用到组中的每个动画上面
    CAAnimationGroup *group = [CAAnimationGroup animation]; group.animations = @[moveAnimation,scaleAnimation,alphaAnimation]; group.duration = 2.0; group.delegate = self; [self.imageView.layer addAnimation:group forKey:nil]; } //图片消失
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ [self.imageView removeFromSuperview]; } //生成路线
-(void)createPath:(UIBezierPath *)path{ [path moveToPoint:self.imageView.center]; CGPoint tartgetPoint = CGPointMake(self.view.bounds.size.width-self.imageView.frame.size.width-20, self.view.bounds.size.height-self.imageView.frame.size.height-20); CGPoint control1 = CGPointMake(self.view.bounds.size.width-self.imageView.frame.size.width-20, self.imageView.frame.origin.y); CGPoint control2 = CGPointMake(self.imageView.frame.origin.x, self.view.bounds.size.height-20-self.imageView.frame.size.height); [path addCurveToPoint:tartgetPoint controlPoint1:control1 controlPoint2:control2]; } @end  补充:动画中止 //中止
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ self.imageView.layer.transform = CATransform3DRotate(self.imageView.layer.transform,M_PI, 1.0, 1.0, 1.0); } 1.6CATransform3D 1)是什么 是一个4X4的矩阵,一个结构体。描述了一个3D图片变形的数据 2)建立 CATransform3DMakeRotation/scale/Translation//这组方法在定值常量的基础上变形
                        CATransform3DScale/Rotate/Translate //这组方法是在传入值的基础上进行变形
===================================================================== 知识点 8、 UIKit Dynamic 动力特效 1. UIKit Dynamic 动力特效 1.1是什么 中文翻译:UIKit 动力、动力模型。。。。iOS7开始的技术。 提供了一个模拟真实世界中力学相关的动画和交互系统,好比,重力、碰撞、吸附等。UIKit Dynamic能够组合 可重用 1.2 UIKit Dynamic架构 a。核心部分:UIDynamicAnimator —>视图的坐标系 b。UIDynamic xx Behavior (行为) 重力 UIGravityBehavior (.magnitude 重力的强度,即加速度) 碰撞 UICollisionBehavior //将场景视图的四周翻译成可碰撞的四个边
                      collision.translatesReferenceBoundsIntoBoundary = YES; 吸附 UIAttachmentBehavior self.attachment.anchorPoint //吸附点 (一个坐标)
                                                       self.attachment.frequency=1;//设置吸附行为的频率(左右晃动的大小)
                       self.attachment.damping=0.1;//设置吸附行为的阻尼(上下弹跳的范围)
 闪烁 推力 综协力 【Demo2_Dynamic】 *****给view添加背景色,显示小方格(方法就是重绘一下图形,利用重写初始化方法:而后设置self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"BackgroundTile"]]; BackgroundView.h #import <UIKit/UIKit.h>

@interface BackgroundView : UIView @property(nonatomic,strong)UIBezierPath *path; @end BackgroundView.m #import "BackgroundView.h"

@implementation BackgroundView //当故事板建立此视图对象时调用此方法,初始化方法
- (id)initWithCoder:(NSCoder *)aDecoder{ self = [super initWithCoder:aDecoder]; if (self) { self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"BackgroundTile"]]; } return self; } //绘制传入的障碍物图形
- (void)drawRect:(CGRect)rect { [[UIColor redColor]setFill]; [[UIColor greenColor]setStroke]; [self.path stroke]; [self.path fill]; } @end
======================================================================================================= 重力 (点击下落就向下,点击中止即中止) ViewController.h ViewController.m #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator *animator; @property(nonatomic,strong)UIGravityBehavior *gravityBehavior; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 1.构建场景
    UIDynamicAnimator *animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view]; self.animator = animator; // 2.建立重力行为对象
    UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:@[self.imageView]]; self.gravityBehavior = gravity; } - (IBAction)begin:(id)sender { // 3.将重力行为添加到场景中
 [self.animator addBehavior:self.gravityBehavior]; } - (IBAction)stop:(id)sender { [self.animator removeBehavior:self.gravityBehavior];//将重力行为从场景中移除
} @end 碰撞(依靠重力下落,而后碰到矩形框,改变成红色而后中止) CollisionViewController.h CollisionViewController.m #import "CollisionViewController.h"
#import "BackgroundView.h"

@interface CollisionViewController ()<UICollisionBehaviorDelegate> @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator *animator; @end

@implementation CollisionViewController - (void)viewDidLoad{ [super viewDidLoad]; self.imageView.transform = CGAffineTransformMakeRotation(M_PI_4); } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; UIDynamicAnimator *animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view]; self.animator = animator; //重力行为
    UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:@[self.imageView]]; //设置重力行为的强度
    gravity.magnitude = 1; [animator addBehavior:gravity]; //碰撞行为
    UICollisionBehavior *collision = [[UICollisionBehavior alloc]initWithItems:@[self.imageView]]; //将场景视图的四周翻译成可碰撞的四个边
    collision.translatesReferenceBoundsIntoBoundary = YES; //添加一条矩形的障碍物
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 360, 280, 30) cornerRadius:10.0]; BackgroundView *myView = (BackgroundView *)self.view; myView.path = path; [myView setNeedsDisplay]; [collision addBoundaryWithIdentifier:@"MyPath1" forPath:path]; collision.collisionDelegate = self; [animator addBehavior:collision]; } //添加代理实现方法 碰撞时方框实现变色
-(void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p{ //NSLog(@"...");
    UIImageView *box = (UIImageView *)item; box.tintColor = [UIColor redColor]; box.image = [box.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; } @end 吸附(设置移动,并在移动到的点与图片的中心点绘制直线,而后移动到哪,图片就吸附到哪,而后有重力,图片还会摆动) AttachmentViewController.h AttachmentViewController.m #import "AttachmentViewController.h"
#import "BackgroundView.h"

@interface AttachmentViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator *animator; @property(nonatomic,strong)UIGravityBehavior *gravity; @property(nonatomic,strong)UIAttachmentBehavior *attachment; @end

@implementation AttachmentViewController - (UIDynamicAnimator *)animator{ if (!_animator) { _animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view]; } return _animator; } - (UIGravityBehavior *)gravity{ if (!_gravity) { _gravity = [[UIGravityBehavior alloc]initWithItems:@[self.imageView]]; } return _gravity; } - (UIAttachmentBehavior *)attachment{ CGPoint attachmentAnchor = CGPointMake(self.imageView.center.x, self.imageView.center.y - 100); if (!_attachment) { _attachment = [[UIAttachmentBehavior alloc]initWithItem:self.imageView attachedToAnchor:attachmentAnchor]; } return _attachment; } - (IBAction)tap:(UIPanGestureRecognizer *)sender { CGPoint location = [sender locationInView:self.view]; //将手势滑动到的点做为吸附行为的锚点
    self.attachment.anchorPoint = location; } - (void)viewDidLoad { [super viewDidLoad]; } - (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [self.animator addBehavior:self.gravity]; self.attachment.action = ^{ //绘制锚点到中心点的悬挂的线
        UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:self.attachment.anchorPoint]; [path addLineToPoint:self.imageView.center]; BackgroundView *bgView = (BackgroundView *)self.view; bgView.path = path; path.lineWidth = 5; [bgView setNeedsDisplay]; }; [self.animator addBehavior:self.attachment]; } @end     改:吸附类 移动的时候会出现绘图绿线和重力做用,当手势中止,一切动做都中止 AttachmentViewController.h AttachmentViewController.m #import "AttachmentViewController.h"
#import "BackgroundView.h"

@interface AttachmentViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator *animator; @property(nonatomic,strong)UIGravityBehavior *gravity; @property(nonatomic,strong)UIAttachmentBehavior *attachment; @end

@implementation AttachmentViewController - (UIDynamicAnimator *)animator{ if (!_animator) { _animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view]; } return _animator; } - (UIGravityBehavior *)gravity{ if (!_gravity) { _gravity = [[UIGravityBehavior alloc]initWithItems:@[self.imageView]]; } return _gravity; } - (UIAttachmentBehavior *)attachment{ //设置锚点
    CGPoint attachmentAnchor = CGPointMake(self.imageView.center.x, self.imageView.center.y - 100); if (!_attachment) { _attachment = [[UIAttachmentBehavior alloc]initWithItem:self.imageView attachedToAnchor:attachmentAnchor]; } return _attachment; } - (IBAction)tap:(UIPanGestureRecognizer *)sender { if (sender.state==UIGestureRecognizerStateBegan) { [self.animator addBehavior:self.gravity]; self.attachment.frequency=1;//设置吸附行为的频率(左右晃动的大小)
        self.attachment.damping=0.1;//设置吸附行为的阻尼(上下弹跳的范围)
 [self drawLine]; [self.animator addBehavior:self.attachment]; }else if(sender.state==UIGestureRecognizerStateChanged){ CGPoint location = [sender locationInView:self.view]; //将手势滑动到的点做为吸附行为的锚点
        self.attachment.anchorPoint = location; [self drawLine]; }else if(sender.state==UIGestureRecognizerStateEnded){ [self.animator removeBehavior:self.gravity]; [self.animator removeBehavior:self.attachment]; BackgroundView*view=(BackgroundView*)self.view; view.path=nil; [view setNeedsDisplay]; } } //执行绘图功能
-(void)drawLine{ self.attachment.action = ^{ //绘制锚点到中心点的悬挂的线
        UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:self.attachment.anchorPoint]; [path addLineToPoint:self.imageView.center]; BackgroundView *bgView = (BackgroundView *)self.view; bgView.path = path; path.lineWidth = 5; [bgView setNeedsDisplay]; }; } @end

    ****补充: 在block块中,只要用到self引用必需要用弱引用 -(void)drawLine{ //弱引用
    __weak UIAttachmentBehavior* weakAttachment=self.attachment; __weak UIImageView*weakImageView=self.imageView; __weak BackgroundView*weakBgView=(BackgroundView*)self.view; self.attachment.action = ^{ //绘制锚点到中心点的悬挂的线
        UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:weakAttachment.anchorPoint]; [path addLineToPoint:weakImageView.center]; BackgroundView *bgView = weakBgView; bgView.path = path; path.lineWidth = 5; [bgView setNeedsDisplay]; }; } 4. 闪烁行为 UISnapBehavior /* 闪烁其实就是快速移动到某一点,使用变形动画也能够作到这个效果, 可是,使用snapBehavior,物体在移动到某点之后 会晃动如下 注意:在animator中不能添加两种一样的特效,因此须要先移除之前的行为,再添加新的行为 */ SnapViewController.h SnapViewController.m #import "SnapViewController.h"

@interface SnapViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator*dynamicAnimator; @property(nonatomic,strong)UISnapBehavior*snapBehavior; @end

@implementation SnapViewController -(UIDynamicAnimator *)dynamicAnimator{ if (!_dynamicAnimator) { _dynamicAnimator=[[UIDynamicAnimator alloc]initWithReferenceView:self.view]; } return _dynamicAnimator; } - (IBAction)pan:(UIPanGestureRecognizer *)sender { CGPoint point=[sender locationInView:self.view]; //先移除原有的闪烁行为 否则只能移一次
 [self.dynamicAnimator removeBehavior:self.snapBehavior]; self.snapBehavior=[[UISnapBehavior alloc]initWithItem:self.imageView snapToPoint:point]; [self.dynamicAnimator addBehavior:self.snapBehavior]; } @end
        
5. 推力行为 UIPushBehavior //推力角度
    self.pushBehavior.angle=M_PI_4;//右下角 //推力大小
    self.pushBehavior.magnitude=2; //激活力 push手势的特别之处:须要激活,不然不起做用
    self.pushBehavior.active=YES; 如:借助移动手势来实现力的方向 #import "PushViewController.h"

@interface PushViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property(nonatomic,strong)UIDynamicAnimator *animator; @property(nonatomic,strong)UIPushBehavior *pushBehavior; @end

/* push手势的特别之处:须要激活,不然不起做用 设置 .active = YES */
@implementation PushViewController - (UIDynamicAnimator *)animator{ if (!_animator) { _animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view]; } return _animator; } - (void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; // 添加碰撞行为,遇到边界则中止
    UICollisionBehavior *collision = [[UICollisionBehavior alloc]initWithItems:@[self.imageView]]; [collision setTranslatesReferenceBoundsIntoBoundaryWithInsets:UIEdgeInsetsMake(self.topLayoutGuide.length, 0,self.bottomLayoutGuide.length, 0) ]; [self.animator addBehavior:collision]; //添加推力行为
    self.pushBehavior = [[UIPushBehavior alloc]initWithItems:@[self.imageView] mode:UIPushBehaviorModeContinuous]; [self.animator addBehavior:self.pushBehavior]; } - (IBAction)tap:(UITapGestureRecognizer *)sender { CGPoint point = [sender locationInView: self.view]; CGPoint center = self.imageView.center; CGFloat angle = atan2(point.y-center.y, point.x-center.x)+M_PI; //powf()函数:求某数的某几回幂 //sqrt()函数:开平方
    CGFloat distance = sqrt(powf((point.x-center.x), 2)+powf((point.y-center.y), 2)); self.pushBehavior.angle = angle; self.pushBehavior.magnitude = distance/10; self.pushBehavior.active = YES; } @end    点击哪就从这个方向施力 练习:SpringMessage 弹簧效果短消息: 1.思路: 利用手指移动的距离,以及item离手指点的位置的远近,产生一个变化的值,用这个值来修改全部collectionView中的item的锚点 2.步骤 step1.首先计算scroll的距离scrollDelta step2.为了获得每一个item与触摸点的之间的距离,还须要知道触摸点的坐标touchLocation。 step3.能够根据距离对每一个锚点进行设置了:简单地计算了原来锚点与触摸点之间的距离distanceFromTouch,并由此计算一个系数。 step4.接下来,对于当前的item,咱们获取其当前锚点位置,而后将其根据scrollDelta的数值和刚才计算的系数,从新设定锚点的位置。 step5.最后须要告诉UIDynamicAnimator已经完成了对锚点的更新,如今能够开始更新物理计算,并随时准备collectionView来取LayoutAttributes的数据了。 SpringLayout.h #import <UIKit/UIKit.h>

@interface SpringLayout : UICollectionViewFlowLayout @property(nonatomic,strong)UIDynamicAnimator *animator; @end SpringLayout.m #import "SpringLayout.h"

/* 1. 为每个布局属性对象添加行为,让布局属性对象成为behavior的主体 2. 控制器再来询问布局属性对象(layoutAttribute) 时,返回具备行为特征的item 3. 每当屏幕滚动一点,就根据触点和各个item的位置的远近,计算出一个有必定变化规律的因子,根据这个因子,有规律的调整每个布局属性对象的attachment Behavior的锚点,就能够实现弹簧效果 */

@implementation SpringLayout //1. 在vc即将跟布局对象要各个布局属性对象以前 //就将每个布局属性对象都添加上 吸附 行为
-(void)prepareLayout{ if (!self.animator) { self.animator = [[UIDynamicAnimator alloc]initWithCollectionViewLayout:self]; //获得整个collectionView的尺寸
        CGSize contentSize = [self collectionViewContentSize]; NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:CGRectMake(0, 0, contentSize.width, contentSize.height)]; //获得整个collectionView中的全部向的 //布局属性对象,从而添加 吸附 行为
        for (UICollectionViewLayoutAttributes *attribute in layoutAttributes) { UIAttachmentBehavior *spring = [[UIAttachmentBehavior alloc]initWithItem:attribute attachedToAnchor:attribute.center]; spring.damping = 0.6; spring.frequency = 0.8; [self.animator addBehavior:spring]; } } } //2.当vc再来询问每个布局属性对象时,返回 //修改过的 布局属性对象,或者说返回已经成为 //吸附行为主体 的 那个布局属性对象
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{ //体系维护对象 按照指定的矩形区域 //返回该范围内的行为主体(布局属性对象)
    return [self.animator itemsInRect:rect] ; } //3.根据vc传入的单元格的坐标,返回该单元格 //对应的那个用来布局这个单元格的部署属性对象 //-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ // return [self.animator layoutAttributesForCellAtIndexPath:indexPath]; //} //4.当边界bounds发生变化时,是否更新边界 //思路:1.不更新边界 // 2.边界发生变化的缘由,是由于有滚动事件发生了 // 虽然不更新边界,但要针对这个用户的操做 // 修改一下锚点,以此出现弹簧效果
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{ UIScrollView *scrollView = self.collectionView; //获取滚动的距离,其实就是坐标系变换的大小
    CGFloat scrollDistance = newBounds.origin.y - scrollView.bounds.origin.y; //手指所在的位置
    CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; //计算和修改每个行为的锚点
    for (UIAttachmentBehavior *spring in self.animator.behaviors) { //由于attribute是 behavior 行为的主体 //因此反过来,从行为上获取 与它绑定的主体 //就须要访问items属性,因为,该行为只关联 //了一个主体,因此取firstObject
        UICollectionViewLayoutAttributes *attributes = [spring.items firstObject]; CGPoint center = attributes.center; CGPoint anchorPoint = spring.anchorPoint; //手指的触点和项的中心点的远近 //根据 项 离 手指触点的远近,产生一组 //不一样大小的 新的anchor值
        CGFloat distance = fabsf(touchLocation.y - anchorPoint.y); // distance是变化的,因此除以最大距离 //也就是一屏幕的高度,取个整,算600 //到底一个小于1的可变化的值 //用这个值做为变化因子,从而使得滚动距离 //与项离触点远近的变化规律相同了
        center.y += scrollDistance*(distance/600); attributes.center = center; // 更新体系内的每个行为的状态
 [self.animator updateItemUsingCurrentState:attributes]; } return NO; } @end ViewController.h ViewController.m #import "ViewController.h"
#import "SpringLayout.h"

@interface ViewController ()<UICollectionViewDataSource>

@end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; SpringLayout *layout = [[SpringLayout alloc]init]; layout.itemSize = CGSizeMake(300,40); layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10); UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout]; collectionView.showsHorizontalScrollIndicator = NO; collectionView.showsVerticalScrollIndicator = NO; [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"MyCell"]; collectionView.dataSource = self; [self.view addSubview:collectionView]; } -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return  50; } -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MyCell" forIndexPath:indexPath]; cell.backgroundColor = [UIColor lightGrayColor]; return cell; } @end  点击屏幕发生晃动 =================================================================== 知识点 9、通知( NSNotification) 1. 通知(Notification) 1.1 是什么? 是一种观察者模式的具体体现 观察者模式:一个对象(A)想知道另外一个对象(B)的状态是否发生了改变。思路就是,在对象B上注册一个观察者,当对象B的状态发生改变时,通知对象A,对象A收到通知后进行相关的处理的一种模式 其中观察者模式的一种解决方案叫作—广播 系统中的通知 就是广播的体现 1.2 好处 一个对象不须要知道消息的接收者是谁,就能够将一些消息发送给须要的接收者 有时,发送消息的对象没法知道有哪些对象,有多少对象接收消息,也不知道对象是否存在 有时,消息的接受者和发送者太远(远 指的不是距离,是关系,如 控制器和视图就很近,但Model离控制器就很远) 1.3 具体用法 1)收听者:找到通知中心 NSNotificationCenter,注册要收听的一个具体频道 addObserver 2)发送者:找到通知中心,建立通知对象(NSNotification),使用通知中心来发送这个消息(postNotification) 3)收听者 收到消息 处理消息(掉个方法) 4)中止收听,不须要收听时,找到通知中心,注销 removeObserver 1.4关键的类 NSNotificationCenter,是一个单例类,使用defaultCenter方法永远返回同一个对象,以此保证中心对象只有一个 NSNotification 通知类(封装通知的内容等信息) 【Demo2_Notification】建立控制台程序 Company.h #import <Foundation/Foundation.h>

@interface Company : NSObject -(void)broadcast; @end Company.m #import "Company.h"

@implementation Company -(void)broadcast{ NSNotificationCenter*center=[NSNotificationCenter defaultCenter]; //发消息
    [center postNotificationName:@"videoUpdate" object:self userInfo:@{@"title": @"锦绣园",@"episode": @"第15集"}]; } @end Vap.h Vap.m #import "Vap.h"

@implementation Vap -(id)init{ if ([super init]) { NSNotificationCenter*center=[NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(updated:) name:@"videoUpdate" object:nil]; } return self; } -(void)updated:(NSNotification*)notification{ NSDictionary*message=notification.userInfo; NSLog(@"%@已经更新到%@",message[@"title"],message[@"episode"]); } -(void)dealloc{ [[NSNotificationCenter defaultCenter]removeObserver:self]; NSLog(@"dealloc执行了"); } @end main.m #import <Foundation/Foundation.h>
#import "Company.h"
#import "Vap.h"
int main(int argc, const char * argv[]) { @autoreleasepool { Company*company=[[Company alloc]init]; Vap*vip=[[Vap alloc]init]; [company broadcast]; NSLog(@"Hello, World!"); } return 0; } 2.键盘通知 键盘弹起的通知名称: UIKeyboardWillShowNotification 键盘收起的通知名称 UIKeyboardWillHideNotification 【Demo3_Keyboard_Notification】 #import "ViewController.h"

@interface ViewController () @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } -(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; // 注册监听
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(keyboardOpen:) name:UIKeyboardWillShowNotification object:nil]; [center addObserver:self selector:@selector(keyboardClosed:) name:UIKeyboardWillHideNotification object:nil]; } -(void)keyboardOpen:(NSNotification *)notification{ NSDictionary *message = notification.userInfo; //获取键盘的起始点(0,264)
    NSValue  *value = message[UIKeyboardFrameEndUserInfoKey]; CGRect rect = [value CGRectValue]; NSLog(@"%f,%f",rect.origin.x,rect.origin.y); //NSLog(@"%@",message);
} -(void)keyboardClosed:(NSNotification *)notification{ NSLog(@"close....."); } //点击右下角关闭键盘
- (IBAction)inputFinished:(UITextField *)sender { [sender resignFirstResponder]; } - (void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } @end qq聊天程序 TRMessage.h #import <Foundation/Foundation.h>

@interface TRMessage : NSObject @property(nonatomic)BOOL fromMe; @property(nonatomic,strong)NSString *content; +(NSMutableArray *) demoData; @end TRMessage.m #import "TRMessage.h"

@implementation TRMessage + (NSMutableArray *)demoData{ TRMessage *message = nil; NSMutableArray *array = [NSMutableArray array]; message = [[TRMessage alloc]init]; message.fromMe = YES; message.content = @"Hello 你好Hello 你好Hello 你好Hello 你好"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = NO; message.content = @"干吗呢"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = YES; message.content = @"没干吗你呢"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = NO; message.content = @"呵呵 呵呵呵"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = YES; message.content = @"今天的大新闻就是苹果手表终于发布了,好喜欢红色的,可是买不起"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = NO; message.content = @"就知道你买不起,那就别买了"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = YES; message.content = @"仍是你送我吧"; [array addObject:message]; message = [[TRMessage alloc]init]; message.fromMe = NO; message.content = @"作梦"; [array addObject:message]; return array; } @end TRMessageCell.h #import <UIKit/UIKit.h>
#import "TRMessage.h"

@interface TRMessageCell : UITableViewCell @property(nonatomic,strong)TRMessage *message; @end TRMessageCell.m #import "TRMessageCell.h"

@interface TRMessageCell () @property (weak, nonatomic) IBOutlet UIImageView *popImageView; @property (weak, nonatomic) IBOutlet UILabel *label; @end

@implementation TRMessageCell #define CELL_MARGIN_TB      4.0     //气泡上下外边距
#define CELL_MARGIN_LR      10.0    //气泡左右外边距

#define CELL_CORNOR         18.0    //气泡圆角半径
#define CELL_TAIL_WIDTH     16.0    //气泡尾巴

#define MAX_WIDTH_OF_TEXT   200.0   //文字宽度限制
#define CELL_PADDING        8.0        //气泡内边距



- (void)setMessage:(TRMessage *)message{ _message = message; self.label.text = self.message.content; //根据消息的来源,对label和image进行定位
    if (self.message.fromMe) {//蓝色气泡 //设置标签内容和图片视图中的气泡图片
        self.label.textColor = [UIColor whiteColor]; UIImage *image = [UIImage imageNamed:@"message_i.png"]; image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(CELL_CORNOR, CELL_CORNOR, CELL_CORNOR, CELL_CORNOR+CELL_TAIL_WIDTH)]; self.popImageView.image = image; //1。定位Label // 先肯定文本的高度
        CGRect rectOfText = CGRectMake(0, 0, MAX_WIDTH_OF_TEXT, 999); rectOfText = [self.label textRectForBounds:rectOfText limitedToNumberOfLines:0]; CGRect frameOfLabel = CGRectZero; frameOfLabel.size = rectOfText.size; frameOfLabel.origin.y = CELL_MARGIN_TB + CELL_PADDING; frameOfLabel.origin.x = self.bounds.size.width - CELL_MARGIN_LR - CELL_TAIL_WIDTH - CELL_PADDING - rectOfText.size.width; self.label.frame = frameOfLabel; //2。定位popImageView的坐标
        CGRect frameOfPop = frameOfLabel; frameOfPop.origin.x -=CELL_PADDING; frameOfPop.origin.y -=CELL_PADDING; frameOfPop.size.width += 2 * CELL_PADDING + CELL_TAIL_WIDTH ; frameOfPop.size.height += 2 * CELL_PADDING; self.popImageView.frame = frameOfPop; //3.设定单元格的bounds
        CGRect bounds = self.bounds; bounds.size.height = frameOfPop.size.height + CELL_MARGIN_TB * 2; self.bounds = bounds; }else{//灰色气泡
        self.label.textColor = [UIColor darkGrayColor]; UIImage *image = [UIImage imageNamed:@"message_other.png"]; image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(CELL_CORNOR, CELL_CORNOR+CELL_TAIL_WIDTH, CELL_CORNOR, CELL_CORNOR)]; self.popImageView.image = image; CGRect rectOfText = CGRectMake(0, 0, MAX_WIDTH_OF_TEXT, 999); rectOfText = [self.label textRectForBounds:rectOfText limitedToNumberOfLines:0]; CGRect frameOfLabel = CGRectZero; frameOfLabel.size = rectOfText.size; frameOfLabel.origin.x = CELL_PADDING+CELL_MARGIN_LR+CELL_TAIL_WIDTH; frameOfLabel.origin.y = CELL_MARGIN_TB + CELL_PADDING; self.label.frame = frameOfLabel; CGRect frameOfPop = frameOfLabel; frameOfPop.origin.x -=(CELL_PADDING + CELL_TAIL_WIDTH); frameOfPop.origin.y -=CELL_PADDING; frameOfPop.size.width += CELL_PADDING*2+CELL_TAIL_WIDTH; frameOfPop.size.height += CELL_PADDING*2; self.popImageView.frame = frameOfPop; CGRect bounds = self.bounds; bounds.size.height = frameOfPop.size.height + CELL_MARGIN_TB *2; self.bounds = bounds; } } @end TRMessageViewController.h #import <UIKit/UIKit.h>

@interface TRMessageViewController : UIViewController @property(nonatomic,strong)NSMutableArray *messages; @end TRMessageViewController.m #import "TRMessageViewController.h"
#import "TRMessage.h"
#import "TRMessageCell.h"

@interface TRMessageViewController ()<UITableViewDataSource,UITableViewDelegate> @property (weak, nonatomic) IBOutlet UITableView *tableView; @property (weak, nonatomic) IBOutlet UIView *inputTextView; @property (weak, nonatomic) IBOutlet UITextField *textField; @end

@implementation TRMessageViewController - (void)viewDidLoad { [super viewDidLoad]; self.title = @"Message"; self.messages = [TRMessage demoData]; [self.tableView registerNib:[UINib nibWithNibName:@"TRMessageCell" bundle:nil] forCellReuseIdentifier:@"Cell"]; // 设置view的背景图
    self.inputTextView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ToolViewBkg_Black.png"]]; } -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1; } -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return self.messages.count; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ TRMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; cell.message = self.messages[indexPath.row]; return cell; } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ //在生成cell的时候,在cell的内部曾经 //根据图片的大小,修改过cell的bounds属性 //随着修改bounds属性,cell的frame就自动被 //修改了,变成咱们根据图片计算出来的高度
    UITableViewCell  *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath]; return cell.frame.size.height; } //注册监听系统键盘的弹起
-(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(keyboardAppear:) name:UIKeyboardWillShowNotification object:nil]; [center addObserver:self selector:@selector(keyboardDisappear:) name:UIKeyboardWillHideNotification object:nil]; } //键盘弹起时
-(void)keyboardAppear:(NSNotification *)notification{ //1.获取键盘的坐标体系
    CGRect frameOfKeyboard = [notification.userInfo[UIKeyboardFrameEndUserInfoKey]CGRectValue]; //2.计算输入框的结束的坐标信息
    CGRect frameOfInputView = self.inputTextView.frame; frameOfInputView.origin.y = frameOfKeyboard.origin.y - frameOfInputView.size.height; //3.计算表格须要滚动的距离
    CGPoint offset = self.tableView.contentOffset; offset.y += frameOfKeyboard.size.height; //4.为inputTextView添加动画
    NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationOptions options = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue]; [UIView animateWithDuration:duration delay:0.0 options:options animations:^{ //设置动画结束时 输入视图的新的位置
         self.inputTextView.frame = frameOfInputView; //动画结束时,修改表格的内容的位置
        self.tableView.contentOffset = offset; } completion:nil]; } //键盘收起时
-(void)keyboardDisappear:(NSNotification *)notification{ CGRect frameOfInputView = self.inputTextView.frame; frameOfInputView.origin.y = self.view.bounds.size.height - frameOfInputView.size.height; CGPoint newOffSet = CGPointMake(0,self.tableView.contentSize.height - self.tableView.frame.size.height); NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationOptions options = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue]; [UIView animateWithDuration:duration delay:0.0 options:options animations:^{ self.inputTextView.frame = frameOfInputView; self.tableView.contentOffset = newOffSet; } completion:nil]; } -(void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center removeObserver:self forKeyPath:UIKeyboardWillShowNotification]; [center removeObserver:self forKeyPath:UIKeyboardWillHideNotification]; } // 点击键盘右下角的return按键
- (IBAction)send:(UITextField *)sender { // NSLog(@"%f",self.tableView.contentSize.height);
    if (![self.textField.text isEqualToString:@""]) { TRMessage *message = [[TRMessage alloc]init]; message.fromMe = YES; message.content = self.textField.text; //清空文本框
        self.textField.text = @""; //message对象添加到数据源
 [self.messages addObject:message]; //更新表视图显示新增长的消息
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.messages.count - 1 inSection:0]; [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; // NSLog(@"%f",self.tableView.contentSize.height);
 } //[self.textField resignFirstResponder];
} @end   故事板TRMessageViewController TRMessageCell   注意:第一个检查器中关闭自动布局,xib中image的第五个检查器中,点亮的红线只有保持上左便可,其余的关闭就能够了。tableView中第四个检查器中,Separator改成None,去掉表格线。Selection 改成No Selection,实现运行的时候,去掉点击时显示的灰色区域 ======================================================================== 知识点 10、Search Bar 搜索栏 1.Search Bar(旧版本) 故事板中的添加了Search Bar 而后到第四个检查器 点击勾上Shows Scope Bar 单元格要记得在第四个检查器中注册identifier为cell Product.h #import <Foundation/Foundation.h> typedef NS_ENUM(NSInteger, ProductType){ ProductTypeDevice, ProductTypeSoftware, ProductTypeOther }; /*定义商品类,包含名称和类别*/
@interface Product : NSObject @property(nonatomic,strong)NSString *name; @property(nonatomic)ProductType type; +(NSArray *)demoData; @end Product.m #import "Product.h"

@implementation Product + (NSArray *)demoData{ Product *p1 = [[Product alloc]init]; p1.name = @"iPhone4s"; p1.type = ProductTypeDevice; Product *p2 = [[Product alloc]init]; p2.name = @"iPhone5s"; p2.type = ProductTypeDevice; Product *p3 = [[Product alloc]init]; p3.name = @"iPhone6"; p3.type = ProductTypeDevice; Product *p4 = [[Product alloc]init]; p4.name = @"iPhone6 Plus"; p4.type = ProductTypeDevice; Product *p5 = [[Product alloc]init]; p5.name = @"OS X Yosemite"; p5.type = ProductTypeSoftware; Product *p6 = [[Product alloc]init]; p6.name = @"Airport Time Capsule"; p6.type = ProductTypeOther; return @[p1,p2,p3,p4,p5,p6]; } @end ProductViewController.h #import <UIKit/UIKit.h>

@interface ProductViewController : UITableViewController @property(nonatomic,strong)NSArray *products; @end ProductViewController.m #import "ProductViewController.h"
#import "Product.h"

@interface ProductViewController ()<UISearchDisplayDelegate>
//声明一个数组,用于存储搜索到的结果内容
@property(nonatomic,strong)NSMutableArray *searchResult; @end

@implementation ProductViewController - (void)viewDidLoad { [super viewDidLoad]; self.products = [Product demoData]; //建立 searchResult 的实例
    self.searchResult = [NSMutableArray array]; //为显示数据的表格注册单元格
    [self.searchDisplayController.searchResultsTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; } /* 当前控制器已是两个标题视图的 代理对象了。 一个表视图指的是TVC自带的表视图 另外一个表视图指的是用于显示搜索结果数据展现的表视图 */

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { //须要区分参数tableView究竟是self.tableView //仍是searchBar的resultTableView //return self.products.count;
    if (tableView == self.searchDisplayController.searchResultsTableView) { return self.searchResult.count; }else{ return self.products.count; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; Product *product = nil; if (tableView == self.view) { product = self.products[indexPath.row]; }else{ product = self.searchResult[indexPath.row]; } cell.textLabel.text = product.name; return cell; } //只要在搜索框中修改了搜索的内容,当即执行此方法
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{ //根据搜索框内写的字符串进行比对 //生成搜索结果 //搜索须要两个数据:文本框中输入的+分段控件中选择的搜索类别
    NSInteger type = self.searchDisplayController.searchBar.selectedScopeButtonIndex; [self updateContentForProductName:searchString andType:type]; return YES; } //只要选择了搜索框下面的分段控件,该方法就执行
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption{ NSString *inputStr = self.searchDisplayController.searchBar.text; [self updateContentForProductName:inputStr andType:searchOption]; return YES; } // 根据输入的文本和选择的类别进行匹配
-(void)updateContentForProductName:(NSString *)searchString andType:(NSInteger )type{ NSMutableArray *array = [NSMutableArray array]; for (Product *p in self.products) { //查看字符串B在A中的位置及占用的长度 //ABCDE -> BCD location = 1 lenght = 3
        NSRange range = [p.name rangeOfString:searchString]; if (range.length > 0 && p.type==type) { [array addObject:p]; } } self.searchResult = array; } @end    2.iOS8 Search Bar (Xcode6) 参考【Demo3_SearchBar_iOS8】 思想:建立类:用于展现搜索结果的控制器的显示模型,在主控制器建立执行搜索动做的控制器并与 本身建立的类相联系,并设置搜索下边的三项分类,而且将searchResultsUpdater和searchBar分别设置为代理,遵照协议<UISearchResultsUpdating,UISearchBarDelegate> Product.h Product.m 同上 MainTableViewController.h #import <UIKit/UIKit.h>

@interface MainTableViewController : UITableViewController @property(nonatomic,strong)NSArray *products; @end MainTableViewController.m #import "MainTableViewController.h"
#import "SearchTableViewController.h"
#import "Product.h"

@interface MainTableViewController ()<UISearchResultsUpdating,UISearchBarDelegate>
//增长属性:用于控制搜索结果显示的控制器
@property(nonatomic,strong)SearchTableViewController *searchResultViewController; @property(nonatomic,strong)UISearchController *searchController; @end

@implementation MainTableViewController - (void)viewDidLoad { [super viewDidLoad]; self.products = [Product demoData]; [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; //建立用于展现搜索结果的控制器实例
    self.searchResultViewController = [[SearchTableViewController alloc]init]; //建立执行搜索动做的控制器,并制定哪一个控制器帮助它显示结果
    self.searchController = [[UISearchController alloc]initWithSearchResultsController:self.searchResultViewController]; //设置搜索控制器的结果更新代理对象
    self.searchController.searchResultsUpdater = self; //设置显示的bar的大小和样式
 [self.searchController.searchBar sizeToFit]; self.searchController.searchBar.scopeButtonTitles = @[@"设备",@"软件",@"其它"]; 显示几个按钮是根据给几个名字 //将搜索bar添加到表头视图
    self.tableView.tableHeaderView = self.searchController.searchBar; self.definesPresentationContext = YES; self.searchController.searchBar.delegate = self; } - (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope{ [self updateSearchResultsForSearchController:self.searchController]; } #pragma mark - UISearchResultUpdating
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController{ //用户输入的要搜索的文本信息
    NSString *searchText = searchController.searchBar.text; //获取选择的scope按钮是哪一个
    NSInteger selectedScopeButton = searchController.searchBar.selectedScopeButtonIndex; NSLog(@"%ld",selectedScopeButton); NSMutableArray *searchResult = [NSMutableArray array]; for (Product *p in self.products) { NSRange range = [p.name rangeOfString:searchText]; if (range.length > 0 && p.type==selectedScopeButton) { [searchResult addObject:p]; } } self.searchResultViewController.resultArray = searchResult; [self.searchResultViewController.tableView reloadData]; } #pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.products.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; Product *p = self.products[indexPath.row]; cell.textLabel.text = p.name; return cell; } @end SearchTableViewController.h #import <UIKit/UIKit.h>

@interface SearchTableViewController : UITableViewController @property(nonatomic,strong)NSArray *resultArray; @end SearchTableViewController.m #import "SearchTableViewController.h"
#import "Product.h"

@interface SearchTableViewController () @end

@implementation SearchTableViewController - (void)viewDidLoad { [super viewDidLoad]; // 注册cell
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell2"]; } #pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.resultArray.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell2" forIndexPath:indexPath]; Product *p = self.resultArray[indexPath.row]; cell.textLabel.text = p.name; return cell; } @end

1.Size Classes 随着苹果设备的增多,屏幕尺寸愈来愈多样化,为了解决适配不一样设备屏幕的问题,从iOS8开始,推出了一项配合Auto layout一块儿用的Size Classes技术 核心理念:抛弃屏幕尺寸的概念,将不一样种类的设备划分到不一样的组合内,制做界面时,关注这一个组别,就等同于对这一个组别下的全部设备进行设计界面。运行时,系统会根据当前设备,判断属于哪一个组别,而后找到对应组别下的AutoLayout原则,依据此原则计算坐标 有哪些组别? 划分组别的标准: 紧凑型 any 标准型 根据右下角肯定,当选到any,便可以包括, 4.应用程序间的通讯 4.1 什么是应用程序间的通信? 一个应用给另外一个应用发点信息过去,但不多,若是说,打开图片库、点击分享、打印、共享 4.2 使用场景 将一个字符串或图片发到微博、微信等应用上 4.3 如何作? 使用一个叫作UIActivityViewController控制器完成任务 4.4 Activity 把共享时要操做的项目叫作Activity,好比说,拷贝、打印——是 Activity中的操做,微信、微博这种Activity叫作分享 【Demo4_UIActivityViewController】 ViewController.h ViewController.m #import "ViewController.h"
#import "StringReverseActivity.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UITextField *textField; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (IBAction)shared:(UIButton *)sender { NSString *text = self.textField.text; //第一步 建立Activity控制器 //activityItems:要传递的信息 //applicationActivities:写nil,系统会 //列出支持的全部activity
    UIActivityViewController *avc = [[UIActivityViewController alloc]initWithActivityItems:@[text] applicationActivities:nil]; //第二步:设置排除的activity
    avc.excludedActivityTypes = @[UIActivityTypeMail]; //第三步:显示出VC
 [self presentViewController:avc animated:YES completion:nil]; } - (IBAction)customActivity:(UIButton *)sender { NSArray *itemToShare = @[@"Hello",@"World",@12345]; //第一步建立自定义的Activity的对象
    StringReverseActivity *srActivity = [[StringReverseActivity alloc]init]; //第二步 添加activity到Activity控制器上
    UIActivityViewController *avc = [[UIActivityViewController alloc]initWithActivityItems:itemToShare applicationActivities:@[srActivity]]; //第三步 推出avc
 [self presentViewController:avc animated:YES completion:nil]; } @end

    4.5自定义的Activity step1:本身写一个类,继承UIActivity step2:实现类内的方法 类内的6个方法必须实现 【Demo4_UIActivityViewController】 接上面的编写 StringReverseActivity.h StringReverseActivity.m #import "StringReverseActivity.h"

@interface StringReverseActivity ()<UIAlertViewDelegate> @property(nonatomic,strong)NSMutableArray *activityItems; @end

@implementation StringReverseActivity //第一个:返回本身的Activity的类型,只要惟一便可
-(NSString *)activityType{ //得到应用程序所在的沙箱的完整路径 //NSStringFromClass是根据类,获取类的名称
    return [[NSBundle mainBundle].bundleIdentifier stringByAppendingFormat:@".%@",NSStringFromClass([self class])]; } //第二个:不要求惟一,但但愿短一点 //返回activity的名称
-(NSString *)activityTitle{ return @"反转"; } //第三个:显示的图片 Retina: 86 X 86 ipad: 110 X 110
-(UIImage *)activityImage{ return  [UIImage imageNamed:@"icon80"]; 图片尺寸不行,因此不显示 } //第四个:将共享的item传过的数据进行检验,看是否能够反转
-(BOOL)canPerformWithActivityItems:(NSArray *)activityItems{ for (id object in activityItems) { if ([object isKindOfClass:[NSString class]]) { //只要有一个string就调用反转方法
            return YES; } } return NO; } //第5个:查找activity的条目,只要有一个item能用就会到达这个方法
- (void)prepareWithActivityItems:(NSArray *)activityItems{ //把全部能反转的item挑出来,放到一个数组中
    NSMutableArray *stringObjects = [NSMutableArray array]; for (id object in activityItems) { if ([object isKindOfClass:[NSString class]]) { [stringObjects addObject:object]; } } self.activityItems = stringObjects; } //第6个:执行activity,编写逻辑---反转
-(void)performActivity{ // 为了保存每个反转后的string
    NSMutableString *reverseString = [[NSMutableString alloc]init]; //反转
    for (NSString *string in self.activityItems) { [reverseString appendString:[self myReverseString:string]]; [reverseString appendString:@"\n"]; } //显示反转的结果
    UIAlertView *alert = [[UIAlertView  alloc]initWithTitle:@"字符串反转" message:reverseString delegate:self cancelButtonTitle:@"肯定" otherButtonTitles:nil]; [alert show]; } //第7个:点击alert中的肯定按钮后,通知activity动做结束
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ [self activityDidFinish:YES]; } //自定义方法:执行字符串的反转
-(NSString *)myReverseString:(NSString *)paramString { NSMutableString *reversed = [[NSMutableString alloc]init]; for (NSInteger index = paramString.length-1; index>=0; index--) { [reversed appendFormat:@"%c",[paramString characterAtIndex:index]]; } return [reversed copy]; } @end 系统默认,去掉了邮件 自定义,多增长了反转 点击反转,只要是字符串就倒过来显示     5.横竖屏的判断 【Demo5_All_Orientation】 1.设置屏幕支持的方向 2.获取即将要旋转到的某个朝向 #import "ViewController.h"

@interface ViewController () @property (weak, nonatomic) IBOutlet UIView *greenVIew; @property (weak, nonatomic) IBOutlet UIButton *button1; @property (weak, nonatomic) IBOutlet UIButton *button2; @property (weak, nonatomic) IBOutlet UIButton *button3; @property (weak, nonatomic) IBOutlet UIButton *button4; @end

@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } //1.设置屏幕支持的方向
- (NSUInteger)supportedInterfaceOrientations{ //设置支持的设备方向
    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape; } //2.获取即将要旋转到的某个朝向
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{ //判断即将到达的朝向,决定选中何种布局
    if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) { //竖屏
 [self layoutPortrait]; }else{ //横屏
 [self layoutLandscape]; } } //自定义的方法,用于竖屏时布局
-(void)layoutPortrait{ self.greenVIew.frame = CGRectMake(20, 20, self.view.bounds.size.width-20-20, self.view.bounds.size.height-20*4-35*2); CGRect frame = CGRectMake(20, self.view.bounds.size.height-20*2-35*2, 130, 35); self.button1.frame = frame; frame.origin.x +=130+20; self.button2.frame = frame; frame.origin.y += (35+20); self.button4.frame = frame; frame.origin.x -= (130+20); self.button3.frame = frame; } //自定义的方法,用于横屏时布局
-(void)layoutLandscape{ } //界面显示前判断好方向,界面显示的时候布置
-(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; //判断出来的那一刻的方向
    UIApplication *app = [UIApplication sharedApplication]; UIInterfaceOrientation orientation = app.statusBarOrientation; if (UIInterfaceOrientationIsPortrait(orientation)) { [self layoutPortrait]; }else{ [self layoutLandscape]; } } @end
相关文章
相关标签/搜索