码迷,mamicode.com
首页 > 其他好文 > 详细

UIView---汇总

时间:2015-12-21 14:10:32      阅读:314      评论:0      收藏:0      [点我收藏+]

标签:

视图、绘图、贴图、手势、变形、布局、动画、动力、特效
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基本概念
            屏幕:很多个晶体组成的,分辨率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];
}


@end
?
            4.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];
}


@end
?
6.绘制图片
            【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]}];
}

@end
?
2.绘制饼图
        写一个视图类:
            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);
    }
}


@end
?
3.自定义Cell,图片是圆角的
         新闻客户端中的自定义Cell,里面的图片做成圆角的
===============================================================
知识点
二、贴图、美化

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
=====================================================================
知识点
三、手势(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;
}


@end
?

4.手势+变形
         
    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后,拖到哪里就放在哪里
====================================================================
知识点
 五、坐标系、触控

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. 支持各种形状—矩形,圆角矩形,椭圆。。。。
=======================================================================================================
知识点 
六、布局
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;
}
@end
?
    1.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;
}

@end

?
3. 手动设置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
?
=======================================================================
知识点
七、动画
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];
        }];
    }];
}

======================================================================
知识点
七、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];
}

@end
?

        1.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 //这组方法是在传入值的基础上进行变形
=====================================================================
知识点
八、 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
?  点击屏幕发生晃动
===================================================================
知识点
九、通知( 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,实现运行的时候,去掉点击时显示的灰色区域
========================================================================
知识点
十、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
?

 

UIView---汇总

标签:

原文地址:http://www.cnblogs.com/52190112cn/p/5063200.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!