iOS开发常用方法--坐标转换

  1. 点(Point)

    (1)- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view;

    /*
     * 描述:将坐标点point从view中转换到当前调用者视图中,返回在当前视图中的坐标点
     * 参数:point -> 一个视图(view)坐标系上的点 
     * 参数:view -> 当前调用者视图。如果是图是nil,那么这个方法将尝试转换基于窗
     * 口的坐标系。否则视图和那个接收者必须属于同一个UIWindow对象。
     * 返回值: 一个转换到接收者(调用者)坐标系的点 
     */
    
     用法: 
         // controllerA 中有一个UITableView, UITableView里有多行UITableVieCell,现在要把UITableViewCell中的某个点Point转换到controllerA的view中
         // 在controllerA中实现:
        CGRect point = [self.view convertPoint:aPoint fromView:cell];
        // 此 point 为在 controllerA 的 view 中的 point
    

    (2)- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view;

    /*
     * 描述:将坐标点point由point所在视图转换到目标视图view中,返回在目标视图view中的坐标点
     * 参数:point -> 一个在当前视图坐标系中的点
     * 参数:view -> 目标视图对象view。如果视图是nil,那么这个方法将会转换成基于窗
     * 口的坐标。否则视图和接收者都要属于同一个UIWindow对象。 
     * 返回值:一个转换到接收者(view)坐标系的点 
     */
    
      用法: 
         // controllerA 中有一个UITableView, UITableView里有多行UITableVieCell,现在要把UITableViewCell中的某个点Point转换到controllerA的view中
         // 在controllerA中实现:
        CGRect point = [cell convertPoint:aPoint toView:self.view];
        // 此 point 为在 controllerA 的 view 中的 point
    
  2. 面(Rect)

    (1)- (CGRect)convertRect:(CGRect)rect fromView:(UIView *)view;

    /*
     * 描述:将rect从view中转换到当前视图中,返回在当前视图中的frame
     * 参数:rect -> 一个视图在当前所在视图坐标系中的frame
     * 参数:view -> 当前坐标系视图对象。如果视图是nil,那么这个方法将会基于窗口来转换。   
     * 否则视图和接收者必须都属于同一个UIWindow对象
     * 返回值:The converted rectangle -> 一个转换过的frame 
     */
    
     用法: 
         // controllerA 中有一个UITableView, UITableView里有多行UITableVieCell,cell上放有一个button,现在要把UITableViewCell中的subview(btn)的frame转换到controllerA的view中
         // 在controllerA中实现:
        CGRect rect = [self.view convertRect:cell.btn.frame fromView:cell];
        // 或当已知btn时:
        CGRect rect = [self.view convertRect:btn.frame fromView:btn.superview];
        // 此 rect 为 btn 在 controllerA 的 view 中的 rect
    

    (2)- (CGRect)convertRect:(CGRect)rect toView:(UIView *)view;

    /*
     * 描述:将rect由rect所在视图转换到目标视图view中,返回在目标视图view中的frame
     * 参数:rect -> 一个视图在当前所在视图坐标系中的frame
     * 参数:view -> 要转换过去的目标视图对象。如果这个是视图是nil,这个方法将会基于窗口坐标系来转换。
     * 否者视图和接收者必须属于同一个UIwindow对象
     * 返回值:The converted rectangle -> 一个转换过的frame
     */
    
     用法:
         // controllerA 中有一个UITableView, UITableView里有多行UITableVieCell,cell上放有一个button,现在要把UITableViewCell中的subview(btn)的frame转换到controllerA的view中
        // 在controllerA中实现:
        CGRect rect = [cell convertRect:cell.btn.frame toView:self.view];
        // 或当已知btn时:
        CGRect rect = [btn.superview convertRect:btn.frame toView:self.view];
        // 此 rect 为 btn 在 controllerA 的 view 中的 rect
    

参考文章:http://www.cnblogs.com/pengyingh/articles/2379476.html UIView 中常见的方法总结

iOS开发-自动布局篇:史上最牛的自动布局教学!

本文我们将提到:

  1. aotulayout(手码)
  2. VFL
  3. aotulayout(Xib)
  4. Masonry(第三方框架)

是不是很期待呢?那就跟着小编走吧!本文Demo地址:https://github.com/JinqianChina/aotulayoutDemo.git

一、AutoLayout介绍

UI布局对于iOS开发者来说并不陌生,在iOS6之前,大家都是通过UI控件的Frame属性和Autoresizing Mask来进行UI布局的。AutoLayout则是苹果公司在iOS6推出的一种基于约束的,描述性的布局系统。自从AutoLayout问世以来,逐步得到了iOS开发者们的青睐,尤其是iPhone6机型尺寸的出现,让AutoLayout从此走向人生巅峰,迎娶白富美,当上UI布局界的老大。~_~,好了,不扯淡了,下面来看看它的特殊之处。

AutoLayout占据UI布局的主要领导位置依赖于它的特殊性:

1.基于约束:和以往定义frame的位置和尺寸不同,AutoLayout的位置确定是以所谓相对位置的约束来定义的,比如x坐标为superView的中心,y坐标为屏幕底部上方10像素等
2.描述性: 约束的定义和各个view的关系使用接近自然语言或者可视化语言(稍后会提到)的方法来进行描述
3.布局系统:即字面意思,用来负责界面的各个元素的位置。

总而言之,AutoLayout为开发者提供了一种不同于传统对于UI元素位置指定的布局方法。以前,不论是在IB里拖放,还是在代码中写,每个UIView都会有自己的frame属性,来定义其在当前视图中的位置和尺寸。使用AutoLayout的话,就变为了使用约束条件来定义view的位置和尺寸。这样的最大好处是一举解决了不同分辨率和屏幕尺寸下view的适配问题,另外也简化了旋转时view的位置的定义,原来在底部之上10像素居中的view,不论在旋转屏幕或是更换设备(iPad或者iPhone5或者以后可能出现的mini iPad)的时候,始终还在底部之上10像素居中的位置,不会发生变化。 总的来说:使用约束条件来描述布局,view的frame会依据这些约束来进行计算。

二、AutoLayout使用原理:

  1. 创建约束,iOS6中新加入了一个类:NSLayoutConstraint。它的约束满足这个公式:

    item1.attribute = multiplier ⨉ item2.attribute + constant
    

    对应的代码为

    //view_1(红色)top 距离self.view的top
    NSLayoutConstraint *view_1TopToSuperViewTop = [NSLayoutConstraint constraintWithItem:view_1
                                                                               attribute:NSLayoutAttributeTop
                                                                               relatedBy:NSLayoutRelationEqual
                                                                                  toItem:self.view
                                                                               attribute:NSLayoutAttributeTop
                                                                              multiplier:1
                                                                                constant:30];
    

    这里对应的约束是“view_1的顶部(y)= self.view的顶部(y)*1 + 30”。

  2. 添加约束,在创建约束之后,需要将其添加到作用的view上。UIView添加约束的实例方法:

    - (void)addConstraint:(NSLayoutConstraint *)constraint NS_AVAILABLE_IOS(6_0);
    - (void)addConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints NS_AVAILABLE_IOS(6_0); 
    

    用来将约束添加到view。在添加时唯一要注意的是添加的目标view要遵循以下规则:

    1.对于两个同层级view之间的约束关系,添加到他们的父view上

    Mou icon

    2.对于两个不同层级view之间的约束关系,添加到他们最近的共同父view上

    Mou icon

    3.对于有层次关系的两个view之间的约束关系,添加到层次较高的父view上

    Mou icon

  3. 刷新约束,可以通过-setNeedsUpdateConstraints和-layoutIfNeeded两个方法来刷新约束的改变,使UIView重新布局。

三、AutoLayout的不同使用方式

OK,到这里我们讲了一堆理论,相信对AutoLayout对不熟悉的童鞋依然比较迷茫,你必须要进行代码的洗礼,才会对它大彻大悟。好的,那么我们开始上代码吧!

如图1:我们需要布局红、绿、蓝三个view位置如图所示,他们距离父视图边距以及相互之间的距离都为30px,红色view和绿色view宽度相等,并且三个view的高度相等。并且在横屏时,他们的位置还是一样保持不变。

Mou icon

Mou icon

Mou icon

如果用传统布局方式利用Frame属性,则需要分情况来判断并改变控件Frame的值以达到适应屏幕的尺寸。下面来看看AutoLayout自动布局的实现方法:

  1. AutoLayout(系统手码)

    - (void)viewDidLoad {
    [super viewDidLoad];
    
    /*
     * 需求
     *
     * 我们需要布局红(view_1)、绿(view_2)、蓝(view_3)三个view位置如图所示,
     * 他们距离父视图边距以及相互之间的距离都为30px,红色view和绿色view宽度相等,
     * 并且三个view的高度相等。并且在横屏时,他们的位置还是一样保持不变。
     *
     */
    
    //1.首先,创建视图控件,添加到self.view上
    
    UIView *view_1 = [[UIView alloc] init];
    view_1.backgroundColor = [UIColor redColor];
    [self.view addSubview:view_1];
    UIView *view_2 = [[UIView alloc] init];
    view_2.backgroundColor = [UIColor greenColor];
    [self.view addSubview:view_2];
    UIView *view_3 = [[UIView alloc] init];
    view_3.backgroundColor = [UIColor blueColor];
    [self.view addSubview:view_3];
    
    //2.然后,记得要把AutoresizingMask布局关掉
    view_1.translatesAutoresizingMaskIntoConstraints = NO;
    view_2.translatesAutoresizingMaskIntoConstraints = NO;
    view_3.translatesAutoresizingMaskIntoConstraints = NO;
    
    //3.接着,添加约束,先添加边距约束,再添加宽高约束(个人习惯)
    /*
     * 添加约束 公式:item1.attribute = multiplier ⨉ item2.attribute + constant
     */
    
    //view_1(红色)top 距离self.view的top
    NSLayoutConstraint *view_1TopToSuperViewTop = [NSLayoutConstraint constraintWithItem:view_1
                                                                               attribute:NSLayoutAttributeTop
                                                                               relatedBy:NSLayoutRelationEqual
                                                                                  toItem:self.view
                                                                               attribute:NSLayoutAttributeTop
                                                                              multiplier:1
                                                                                constant:30];
    //view_1(红色)left 距离self.view的left
    NSLayoutConstraint *view_1LeftToSuperViewLeft = [NSLayoutConstraint constraintWithItem:view_1
                                                                                 attribute:NSLayoutAttributeLeft
                                                                                 relatedBy:NSLayoutRelationEqual
                                                                                    toItem:self.view
                                                                                 attribute:NSLayoutAttributeLeft
                                                                                multiplier:1
                                                                                  constant:30];
    //view_1(红色)right 距离view_2(绿色)的left
    NSLayoutConstraint *view_1RightToview_2Left = [NSLayoutConstraint constraintWithItem:view_2
                                                                               attribute:NSLayoutAttributeLeft
                                                                               relatedBy:NSLayoutRelationEqual
                                                                                  toItem:view_1
                                                                               attribute:NSLayoutAttributeRight
                                                                              multiplier:1
                                                                                constant:30];
    //view_1(红色)bottom 距离view_3(蓝色)的top
    NSLayoutConstraint *view_1BottomToview_3Top = [NSLayoutConstraint constraintWithItem:view_1
                                                                               attribute:NSLayoutAttributeBottom
                                                                               relatedBy:NSLayoutRelationEqual
                                                                                  toItem:view_3
                                                                               attribute:NSLayoutAttributeTop
                                                                              multiplier:1
                                                                                constant:- 30];
    
    //view_2(绿色)right 距离self.view的right
    NSLayoutConstraint *view_2RightToSuperViewRight = [NSLayoutConstraint constraintWithItem:view_2
                                                                                   attribute:NSLayoutAttributeRight
                                                                                   relatedBy:NSLayoutRelationEqual
                                                                                      toItem:self.view
                                                                                   attribute:NSLayoutAttributeRight
                                                                                  multiplier:1
                                                                                    constant:- 30];
    
    //view_2(绿色)centerY 和 view_1(红色)的centerY 一致
    NSLayoutConstraint *view_2CenterYToView_1CenterY = [NSLayoutConstraint constraintWithItem:view_2
                                                                                    attribute:NSLayoutAttributeCenterY
                                                                                    relatedBy:NSLayoutRelationEqual
                                                                                       toItem:view_1
                                                                                    attribute:NSLayoutAttributeCenterY
                                                                                   multiplier:1
                                                                                     constant:0];
    
    //view_3(蓝色)left 距离 self.view left
    NSLayoutConstraint *view_3LeftToSuperViewLeft = [NSLayoutConstraint constraintWithItem:view_3
                                                                                 attribute:NSLayoutAttributeLeft
                                                                                 relatedBy:NSLayoutRelationEqual
                                                                                    toItem:self.view
                                                                                 attribute:NSLayoutAttributeLeft
                                                                                multiplier:1
                                                                                  constant:30];
    
    //view_3(蓝色)right 距离 self.view right
    NSLayoutConstraint *view_3RightToSuperViewRight = [NSLayoutConstraint constraintWithItem:view_3
                                                                                   attribute:NSLayoutAttributeRight
                                                                                   relatedBy:NSLayoutRelationEqual
                                                                                      toItem:self.view
                                                                                   attribute:NSLayoutAttributeRight
                                                                                  multiplier:1
                                                                                    constant:- 30];
    
    //view_3(蓝色)Bottom 距离 self.view bottom
    NSLayoutConstraint *view_3BottomToSuperViewBottom = [NSLayoutConstraint constraintWithItem:view_3
                                                                                     attribute:NSLayoutAttributeBottom
                                                                                     relatedBy:NSLayoutRelationEqual
                                                                                        toItem:self.view
                                                                                     attribute:NSLayoutAttributeBottom
                                                                                    multiplier:1
                                                                                      constant:- 30];
    
    //view_1(红色)width 和view_2(绿色)的width相等
    NSLayoutConstraint *view_1WidthToview_2Width = [NSLayoutConstraint constraintWithItem:view_2
                                                                                attribute:NSLayoutAttributeWidth
                                                                                relatedBy:NSLayoutRelationEqual
                                                                                   toItem:view_1
                                                                                attribute:NSLayoutAttributeWidth
                                                                               multiplier:1
                                                                                 constant:0];
    
    //view_1(红色)height 和view_2(绿色)的height相等
    NSLayoutConstraint *view_1HeightToview_2Height = [NSLayoutConstraint constraintWithItem:view_2
                                                                                  attribute:NSLayoutAttributeHeight
                                                                                  relatedBy:NSLayoutRelationEqual
                                                                                     toItem:view_1
                                                                                  attribute:NSLayoutAttributeHeight
                                                                                 multiplier:1
                                                                                   constant:0];
    
    //view_1(红色)height 和 view_3(蓝色)的height相等
    NSLayoutConstraint *view_1HeightToview_3Height = [NSLayoutConstraint constraintWithItem:view_3
                                                                                  attribute:NSLayoutAttributeHeight
                                                                                  relatedBy:NSLayoutRelationEqual
                                                                                     toItem:view_1
                                                                                  attribute:NSLayoutAttributeHeight
                                                                                 multiplier:1
                                                                                   constant:0];
    
    //添加约束,因为view_1、2、3是同层次关系,且他们公有的父视图都是self.view,所以这里把约束都添加到self.view上即可
    [self.view addConstraints:@[view_1TopToSuperViewTop,view_1LeftToSuperViewLeft,view_1RightToview_2Left,view_2RightToSuperViewRight,view_1WidthToview_2Width,view_1BottomToview_3Top,view_2CenterYToView_1CenterY,view_3LeftToSuperViewLeft,view_3RightToSuperViewRight,view_3BottomToSuperViewBottom,view_1HeightToview_2Height,view_1HeightToview_3Height]];
    
    [self.view layoutIfNeeded];
    }
    

    看到这里,相信大家要哭了吧,为毛就写这三个视图要这么麻烦,没错,小编这里就是用来恶心你的,哈哈!其实,我去研究它的时候,也是被恶心的要死,没办法,为了帮助大家对AutoLayout进行深入理解,小编也是拼了(ps:其实我在项目中基本不用这个系统手码的)。还好,苹果还给我们提供了一种可视化自然语言用于自动布局的约束:VFL(Visual Format Language),简化了添加约束。

  2. VFL约束

    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    /*
     * 需求
     *
     * 我们需要布局红(view_1)、绿(view_2)、蓝(view_3)三个view位置如图所示,
     * 他们距离父视图边距以及相互之间的距离都为30px,红色view和绿色view宽度相等,
     * 并且三个view的高度相等。并且在横屏时,他们的位置还是一样保持不变。
     *
     */
    
    //1.首先,创建视图控件,添加到self.view上
    
    UIView *view_1 = [[UIView alloc] init];
    view_1.backgroundColor = [UIColor redColor];
    [self.view addSubview:view_1];
    UIView *view_2 = [[UIView alloc] init];
    view_2.backgroundColor = [UIColor greenColor];
    [self.view addSubview:view_2];
    UIView *view_3 = [[UIView alloc] init];
    view_3.backgroundColor = [UIColor blueColor];
    [self.view addSubview:view_3];
    
    //2.然后,记得要把AutoresizingMask布局关掉
    view_1.translatesAutoresizingMaskIntoConstraints = NO;
    view_2.translatesAutoresizingMaskIntoConstraints = NO;
    view_3.translatesAutoresizingMaskIntoConstraints = NO;
    
    //3.接着,添加约束
    
    // 间距
    NSNumber *margin = @(30);
    NSNumber *spacing = @(30);
    NSDictionary *views = NSDictionaryOfVariableBindings(view_1,view_2,view_3);
    
    // 添加水平方向的约束1
    NSString *vfl = @"H:|-margin-[view_1]-spacing-[view_2(==view_1)]-margin-|";
    NSDictionary *mertrics = NSDictionaryOfVariableBindings(margin,spacing);
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:vfl options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:mertrics views:views];
    [self.view addConstraints:constraints];
    
    // 添加水平方向的约束2
    NSString *vfl1 = @"H:|-margin-[view_3]-margin-|";
    NSDictionary *mertrics1 = NSDictionaryOfVariableBindings(margin,spacing);
    
    NSArray *constraints1 = [NSLayoutConstraint constraintsWithVisualFormat:vfl1 options:kNilOptions metrics:mertrics1 views:views];
    [self.view addConstraints:constraints1];
    
    // 添加竖直方向的约束
    NSString *vfl2 = @"V:|-margin-[view_1]-spacing-[view_3(==view_1)]-margin-|";
    NSDictionary *mertrics2 = NSDictionaryOfVariableBindings(margin, spacing);
    NSArray *constraints2 = [NSLayoutConstraint constraintsWithVisualFormat:vfl2 options:kNilOptions metrics:mertrics2 views:views];
    [self.view addConstraints:constraints2];
    }
    

    看了VFL语言约束,是不是瞬间感觉高大上了许多,按照我们所想,依次写出约束VFL语句即可。这样虽然比系统手码方便多了,但是仍然需要写很多代码,小编下面要告诉你的是,不用写一行约束代码就能完成上面约束需求,那就是Xib可视化添加约束,下面来看看吧!

  3. Xib可视化添加约束

    (1)首先,先拖拽三个UIview视图,如图。注意:这里我们只是暂时大致摆了一下位置,还没有添加约束。

    Mou icon

    (2)view_1红色视图添加约束,如图,添加上和左距离父视图都是30px

    Mou icon

    (3)view_2绿色视图添加约束,如图,添加左和右分别距离view_1和父视图的距离都是30px

    Mou icon

    (4)view_2添加约束,如图,直接点击view_2拖拽到view_1上,然后选择Center Vertically、Equal Widths和Equal Heights,则添加了view_2约束:竖直方向上中心和view_1一致、宽度和高度也和view_1相等

    Mou icon

    Mou icon

    (5)view_3蓝色视图添加约束,如图,添加左、下、右距离父视图的值都为30,上距离view_1的距离为30,并且高度和view_1相等

    Mou icon

    (7)如图,约束已经添加完成,点击左侧的黄色警告补全视图差值

    Mou icon

    (8)如图,则是我们布局完成后的Xib,运行效果就是开头那个GIF图效果,是不是很炫酷!

    Mou icon

    Mou icon

    到这里,是不是感觉很神奇了呢,不用一行代码,就可以完成上述那么多代码实现的效果。至此,Aotulayout布局已经基本介绍完了,对了,还有一个第三方库Masonry。

  4. Masonry第三方库

    Masonry是一个轻量级的布局框架,拥有自己的描述语法,采用更优雅的链式语法封装自动布局,简洁明了 并具有高可读性,而且同时支持iOS和Max OS X。

    下面简单说明一下Masonry:

    先来看一段官方的sample code来认识一下Masonry

    [view1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(superview).with.insets(padding);
    }];
    

    我们看到block里面的那句话: make edges equalTo superview with insets。这里通过链式的自然语言,就把view1给autolayout设置好了,看着是不是挺简单的?更符合我们编程的思想。

    再来看一看它的属性:

    @property (nonatomic, strong, readonly) MASViewAttribute *left;
    @property (nonatomic, strong, readonly) MASViewAttribute *top;
    @property (nonatomic, strong, readonly) MASViewAttribute *right;
    @property (nonatomic, strong, readonly) MASViewAttribute *bottom;
    @property (nonatomic, strong, readonly) MASViewAttribute *leading;
    @property (nonatomic, strong, readonly) MASViewAttribute *trailing;
    @property (nonatomic, strong, readonly) MASViewAttribute *width;
    @property (nonatomic, strong, readonly) MASViewAttribute *height;
    @property (nonatomic, strong, readonly) MASViewAttribute *centerX;
    @property (nonatomic, strong, readonly) MASViewAttribute *centerY;
    @property (nonatomic, strong, readonly) MASViewAttribute *baseline;
    @property (nonatomic, strong, readonly) MASViewAttribute *(^attribute)(NSLayoutAttribute attr);
    
    #if TARGET_OS_IPHONE
    
    @property (nonatomic, strong, readonly) MASViewAttribute *leftMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *rightMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *topMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *bottomMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *leadingMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *trailingMargin;
    @property (nonatomic, strong, readonly) MASViewAttribute *centerXWithinMargins;
    @property (nonatomic, strong, readonly) MASViewAttribute *centerYWithinMargins;
    

    是不是觉得很眼熟?没错,它和我们系统的NSLayoutConstraint类下的NSLayoutAttribute枚举一致,这样就不难理解了,Masonry其实就是把我们系统的NSLayoutConstraint类等Aotulayout布局相关进行了封装,曝露出比较简单易懂(链式的自然语言)的Aotulayout接口,方便广大iOS开发者使用。

    typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
    NSLayoutAttributeLeft = 1,
    NSLayoutAttributeRight,
    NSLayoutAttributeTop,
    NSLayoutAttributeBottom,
    NSLayoutAttributeLeading,
    NSLayoutAttributeTrailing,
    NSLayoutAttributeWidth,
    NSLayoutAttributeHeight,
    NSLayoutAttributeCenterX,
    NSLayoutAttributeCenterY,
    NSLayoutAttributeBaseline,
    NSLayoutAttributeLastBaseline = NSLayoutAttributeBaseline,
    NSLayoutAttributeFirstBaseline NS_ENUM_AVAILABLE_IOS(8_0),
    
    NSLayoutAttributeLeftMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeRightMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTopMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeBottomMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeLeadingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTrailingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterXWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterYWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    
    NSLayoutAttributeNotAnAttribute = 0
    };
    

    好了,简单说明之后,让我们更实际的来些代码吧!同样是上面的需求哦!come on
    首先,要导入Masonry库文件,这里要打一下广告了,Masonry 源码地址:https://github.com/Masonry/Masonry 你可以直接下载,然后将文件拖入工程,也可以使用cocoapods导入,如果不明白cocoapods怎么用的,可以看一下小编的一篇关于cocoapods的介绍:http://www.jianshu.com/p/c23eeb43438b

    OK,看看Masonry神奇的代码吧!

    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    /*
     * 需求
     *
     * 我们需要布局红(view_1)、绿(view_2)、蓝(view_3)三个view位置如图所示,
     * 他们距离父视图边距以及相互之间的距离都为30px,红色view和绿色view宽度相等,
     * 并且三个view的高度相等。并且在横屏时,他们的位置还是一样保持不变。
     *
     */
    
    //1.首先,创建视图控件,添加到self.view上
    
    UIView *view_1 = [[UIView alloc] init];
    view_1.backgroundColor = [UIColor redColor];
    [self.view addSubview:view_1];
    UIView *view_2 = [[UIView alloc] init];
    view_2.backgroundColor = [UIColor greenColor];
    [self.view addSubview:view_2];
    UIView *view_3 = [[UIView alloc] init];
    view_3.backgroundColor = [UIColor blueColor];
    [self.view addSubview:view_3];
    
    //2.然后,记得要把AutoresizingMask布局关掉
    view_1.translatesAutoresizingMaskIntoConstraints = NO;
    view_2.translatesAutoresizingMaskIntoConstraints = NO;
    view_3.translatesAutoresizingMaskIntoConstraints = NO;
    
    //3.接着,添加约束
    
    __weak __typeof(self) weakSelf = self;//这里用一个弱引用来表示self,用于下面的Block中
    
    //先确定view_1的约束
    [view_1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(weakSelf.view.mas_top).with.offset(30); //view_1的上,距离self.view是30px
        make.left.equalTo(weakSelf.view.mas_left).with.offset(30); //view_1de左,距离self.view是30px
    }];
    
    //然后确定view_2的约束
    [view_2 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(view_1.mas_centerY).with.offset(0); //view2 Y方向上的中心线和view_1相等
        make.left.equalTo(view_1.mas_right).with.offset(30); //view2 的左距离view_1的右距离为30px
        make.right.equalTo(weakSelf.view.mas_right).with.offset(-30); //view_2的右距离self.view30px
        make.width.equalTo(view_1); //view_2的宽度和view_1相等
        make.height.equalTo(view_1); //view_2的高度和view_1相等
    }];
    
    //最后确定view_3的约束
    [view_3 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(view_1.mas_bottom).with.offset(30); //view_3的上距离view_1的底部 30px
        make.left.equalTo(weakSelf.view.mas_left).with.offset(30); //view_3的左距离self.view 30px
        make.bottom.equalTo(weakSelf.view.mas_bottom).with.offset(30);//view_3的底部距离self.view 30px
        make.right.equalTo(weakSelf.view.mas_right).with.offset(-30); //view_3的右距离self.view 30px
        make.height.equalTo(view_1);//view_3的高度和view_1相等
    }];
    }
    

    运行效果就是上面的GIF图,Masonry虽然也写了不少代码,但是他看起来比较简单易懂,在实战项目中,我们可以用Masonry作为Xib的辅助工具使用,利用代码处理一些动态的约束。

    最后说明一下,在Masonry中能够添加autolayout约束有三个函数:

    - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))block;
    - (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block;
    - (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block;
    /*
    mas_makeConstraints 只负责新增约束 Autolayout不能同时存在两条针对于同一对象的约束 否则会报错 
    mas_updateConstraints 针对上面的情况 会更新在block中出现的约束 不会导致出现两个相同约束的情况
    mas_remakeConstraints 则会清除之前的所有约束 仅保留最新的约束
    三种函数善加利用 就可以应对各种情况了
    */
    

喜欢的童鞋,动一下小手点击喜欢和关注喔!小编在这里附上以上四种自动布局Demo:https://github.com/JinqianChina/aotulayoutDemo.git

参考文章:
http://www.cocoachina.com/ios/20141219/10702.html Masonry介绍与使用实践:快速上手Autolayout

ios页面传值:正向、反向

iOS开发中,页面传值是很常见的,但是页面传值你究竟知道多少呢?笔者这篇文章就是给大家介绍一下页面传值的具体方式,有不足之处,欢迎大家指正,希望能和大家共同进步。说明一下:这里所说的正向、反向传值是指相关联的两个页面间的传值。

目前我所了解和掌握的传值方式有:属性传值、代理传值、Block传值、KVO传值、通知传值、单例传值、KVC传值。

下面我们来一一看下它们究竟是怎样进行操作和传值的呢?

假设我们现在有控制器(页面)A和控制器(页面)B,A->push->B,即A是B的上一个页面(控制器)。

  1. 属性传值
    用法:正向传值
    需求:当A-push到B时,B中有一个Label需要显示从A中的一个TextField输入的内容,这时我们需要用到正向传值。

    A控制器.m文件:

    #import "A_ViewController.h"
    #import "B_ViewController.h"
    
    @interface A_ViewController ()
    
    @property (nonatomic, strong) UITextField *aTextField;
    
    @end
    
    @implementation A_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"A";
        self.view.backgroundColor = [UIColor whiteColor];
        self.aTextField = [[UITextField alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        self.aTextField.layer.borderColor = [UIColor grayColor].CGColor;
        self.aTextField.layer.borderWidth = 1;
        [self.view addSubview:self.aTextField];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"传到B" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
    }
    
    - (void)buttonAction:(UIButton *)sender {
    
        /**
         什么时候可以用 属性 传值
    
         A 传到 B,正向传值
    
         B 在 A页面 提前初始化
    
         **/
    
        B_ViewController *bViewController = [[B_ViewController alloc] init];
        bViewController.string = self.aTextField.text;
        [self.navigationController pushViewController:bViewController animated:YES];
    
    }
    
    @end
    

    B控制器.h文件:

    #import <UIKit/UIKit.h>
    
    @interface B_ViewController : UIViewController
    
    @property (nonatomic, copy) NSString *string;
    
    @end
    

    B控制器.m文件:

    #import "B_ViewController.h"
    
    @interface B_ViewController ()
    
    @end
    
    @implementation B_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"B";
        self.view.backgroundColor = [UIColor whiteColor];
    
        self.view.backgroundColor = [UIColor whiteColor];
        UILabel *bLabel = [[UILabel alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        bLabel.layer.borderColor = [UIColor grayColor].CGColor;
        bLabel.layer.borderWidth = 1;
        [self.view addSubview:bLabel];
    
        bLabel.text = self.string;
    }
    
    @end
    
  2. 代理传值
    用法:反向传值:
    需求:A-push到B,当B消失的时候,A中有一个Label需要显示从B中的一个TextField输入的内容,这时我们需要用到反向传值。

    A控制器.m文件:

    #import "A_ViewController.h"
    #import "B_ViewController.h"
    
    @interface A_ViewController () <BToADelegate>
    
    @property (nonatomic, strong) UILabel *aLabel;
    
    @end
    
    @implementation A_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"A";
        self.view.backgroundColor = [UIColor whiteColor];
        self.aLabel = [[UILabel alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        self.aLabel.layer.borderColor = [UIColor grayColor].CGColor;
        self.aLabel.layer.borderWidth = 1;
        [self.view addSubview:self.aLabel];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"push到B" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
    }
    
    -(void)buttonAction:(UIButton *)sender {
    
        B_ViewController *bViewController = [[B_ViewController alloc] init];
        //设置代理
        bViewController.delegate = self;
        [self.navigationController pushViewController:bViewController animated:YES];
    }
    
    /**
     什么时候可以用 代理 传值
    
     B 传到 A,反向传值
    
     B 在 A页面 初始化
    
     设置A为B的代理
    
     执行代理方法
    
     **/
    - (void)transferString:(NSString *)string {
    
        self.aLabel.text = string;
    }
    
    @end
    

    B控制器.h文件:

    #import <UIKit/UIKit.h>
    
    // 声明代理
    @protocol BToADelegate <NSObject>
    
    // 代理方法
    - (void)transferString:(NSString *)string;
    
    @end
    
    @interface B_ViewController : UIViewController
    
    // 代理属性
    @property (nonatomic, weak) id<BToADelegate> delegate;
    
    @end
    

    B控制器.m文件:

    #import "B_ViewController.h"
    
    @interface B_ViewController ()
    
    @property (nonatomic, strong) UITextField *bTextField;;
    
    @end
    
    @implementation B_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"B";
        self.view.backgroundColor = [UIColor whiteColor];
    
        self.view.backgroundColor = [UIColor whiteColor];
        self.bTextField = [[UITextField alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        self.bTextField.layer.borderColor = [UIColor grayColor].CGColor;
        self.bTextField.layer.borderWidth = 1;
        [self.view addSubview:self.bTextField];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"传值A" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
    }
    
    - (void)buttonAction:(UIButton *)sender {
    
        // 判断有没有代理以及代理是否响应代理方法
        if (self.delegate && [self.delegate respondsToSelector:@selector(transferString:)]) {
            [self.delegate transferString:self.bTextField.text];
        }
    
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    
    @end
    
  3. Block传值
    用法:反向传值:
    需求:A-push到B,当B消失的时候,A中有一个Label需要显示从B中的一个TextField输入的内容,这时我们需要用到反向传值。

    A控制器.m文件:

    #import "A_ViewController.h"
    #import "B_ViewController.h"
    
    @interface A_ViewController ()
    
    @property (nonatomic ,strong) UILabel *aLabel;
    
    @end
    
    @implementation A_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"A";
        self.view.backgroundColor = [UIColor whiteColor];
        self.aLabel = [[UILabel alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        self.aLabel.layer.borderColor = [UIColor grayColor].CGColor;
        self.aLabel.layer.borderWidth = 1;
        [self.view addSubview:self.aLabel];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"push到B" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
    }
    
    - (void)buttonAction:(UIButton *)sender {
    
        B_ViewController *bViewController = [[B_ViewController alloc] init];
    
        __weak __typeof(self) weakSelf = self;
        // block 回调接收
        [bViewController setBlock:^(NSString *string){
            weakSelf.aLabel.text = string;
        }];
    
        [self.navigationController pushViewController:bViewController animated:YES];
    }
    

    B控制器.h文件:

    #import <UIKit/UIKit.h>
    
    // 定义一个block
    typedef void(^BToAblock)(NSString *string);
    
    @interface B_ViewController : UIViewController
    
    // block 属性
    @property (nonatomic, copy)BToAblock block;
    
    @end
    

    B控制器.m文件:

    #import "B_ViewController.h"
    
    @interface B_ViewController ()
    
    @property (nonatomic, strong) UITextField *bTextField;
    
    @end
    
    @implementation B_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"B";
        self.view.backgroundColor = [UIColor whiteColor];
    
        self.view.backgroundColor = [UIColor whiteColor];
        self.bTextField = [[UITextField alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        self.bTextField.layer.borderColor = [UIColor grayColor].CGColor;
        self.bTextField.layer.borderWidth = 1;
        [self.view addSubview:self.bTextField];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"传值A" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
    }
    
    - (void)buttonAction:(UIButton *)sender {
        /**
         Blcok 传值
    
         反向传值
    
         B 传到 A
         */
        _block(self.bTextField.text);
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    
    @end
    
  4. KVO传值
    用法:反向传值:
    需求:A-push到B,当B消失的时候,A中有一个Label需要显示从B中的一个TextField输入的内容,这时我们需要用到反向传值。

    A控制器.m文件:

    #import "A_ViewController.h"
    #import "B_ViewController.h"
    
    @interface A_ViewController ()
    
    @property (nonatomic, strong) UILabel *aLabel;
    @property (nonatomic, strong) B_ViewController *bViewController;
    
    @end
    
    @implementation A_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"A";
        self.view.backgroundColor = [UIColor whiteColor];
        self.aLabel = [[UILabel alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        self.aLabel.layer.borderColor = [UIColor grayColor].CGColor;
        self.aLabel.layer.borderWidth = 1;
        [self.view addSubview:self.aLabel];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"push到B" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
        /**
         KVO 创建 三步一定要写
            1. 注册观察者
            2. KVO的回调
            3. 移除观察者
    
         */
    
        // B 传到 A ,反向传值
        //注册观察者,注意:观察者的注册和移除要对应,如果移除时发现没有注册观察者,程序会crash
         self.bViewController = [[B_ViewController alloc] init];
        [self.bViewController addObserver:self forKeyPath:@"string" options:NSKeyValueObservingOptionNew context:nil];
    }
    
    - (void)buttonAction:(UIButton *)sender {
    
        [self.navigationController pushViewController:self.bViewController animated:YES];
    
    }
    
    // KVO的回调
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    
        if ([keyPath isEqualToString:@"string"]) {
            self.aLabel.text = self.bViewController.string;
        }
    
    }
    // KVO 的移除方式  (和通知一样要移除)
    - (void)dealloc {
    
        [self.bViewController removeObserver:self forKeyPath:@"string"];
    }
    
    @end
    

    B控制器.h文件:

    #import <UIKit/UIKit.h>
    
    @interface B_ViewController : UIViewController
    
    @property (nonatomic, copy) NSString *string;
    
    @end
    

    B控制器.m文件:

    #import "B_ViewController.h"
    
    @interface B_ViewController ()
    
    @property (nonatomic, strong) UITextField *bTextField;
    
    @end
    
    @implementation B_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"B";
        self.view.backgroundColor = [UIColor whiteColor];
    
        self.view.backgroundColor = [UIColor whiteColor];
        self.bTextField = [[UITextField alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        self.bTextField.layer.borderColor = [UIColor grayColor].CGColor;
        self.bTextField.layer.borderWidth = 1;
        [self.view addSubview:self.bTextField];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"传值A" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
    }
    
    - (void)buttonAction:(UIButton *)sender {
        // KVO
        // 把self.bTextfield.text 赋值给当前属性
        // 在A中 监听 当前属性
        self.string = self.bTextField.text;
    
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    
    @end
    
  5. 通知传值
    用法:正向传值
    需求:当A-push到B时,B中有一个Label需要显示从A中的一个TextField输入的内容,这时我们需要用到正向传值。

    用法:反向传值:
    需求:A-push到B,当B消失的时候,A中有一个Label需要显示从B中的一个TextField输入的内容,这时我们需要用到反向传值。

    我们在此将两种传值情况写到一个Demo中,所以将上述Label换为Textfield即可,如下:

    A控制器.m文件:

    #import "A_ViewController.h"
    #import "B_ViewController.h"
    
    @interface A_ViewController ()
    
    @property (nonatomic, strong) UITextField *aTextField;
    
    @end
    
    @implementation A_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"A";
        self.view.backgroundColor = [UIColor whiteColor];
        self.aTextField = [[UITextField alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        self.aTextField.layer.borderColor = [UIColor grayColor].CGColor;
        self.aTextField.layer.borderWidth = 1;
        [self.view addSubview:self.aTextField];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"传到B" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
        // 接收通知
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tzAction:) name:@"B2A" object:nil];
    }
    
    - (void)buttonAction:(UIButton *)sender {
    
        // 通知传值 一般是用于回传
    
        // 现在是 A传到B,正向传值
    
        // 发送通知的方法 要写在执行方法里面
    
        B_ViewController *bViewController = [[B_ViewController alloc] init];
    
        [[NSNotificationCenter defaultCenter] postNotificationName:@"A2B" object:nil userInfo:@{@"key":self.aTextField.text}];
    
        [self.navigationController pushViewController:bViewController animated:YES];
    
    }
    
    // 回调通知
    - (void)tzAction:(NSNotification *)sender {
    
        self.aTextField.text = sender.userInfo[@"key"];
    }
    
    // 移除通知
    - (void)dealloc {
    
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    
    @end
    

    B控制器.m文件:

    #import "B_ViewController.h"
    
    @interface B_ViewController ()
    
    @property (nonatomic, strong) UITextField *bTextField;
    
    @end
    
    @implementation B_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"B";
        self.view.backgroundColor = [UIColor whiteColor];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"传值A" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    }
    
    //如果是从A传到B的话,B.m里要创建一个init方法,在里面写监听并在里面创建接收容器才能成功(因为程序先执行init方法再到viewDidLoad方法,当传值过去时在init就开始监听,如果这里没有创建textField接收,那就传不过去了,所以要在init里同时创建接收器(生命周期的问题));
    -(instancetype)init
    {
        if (self = [super init]) {
    
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tzAction:) name:@"A2B" object:nil];
    
            self.bTextField = [[UITextField alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
            self.bTextField.layer.borderColor = [UIColor grayColor].CGColor;
            self.bTextField.layer.borderWidth = 1;
            [self.view addSubview:self.bTextField];
    
        }
    
        return self;
    }
    
    //接收通知
    - (void)tzAction:(NSNotification *)sender {
    
        self.bTextField.text = sender.userInfo[@"key"];
    
    }
    
    // 移除通知
    - (void)dealloc  {
    
        // 移除所有
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    
        // 移除某个
        // [[NSNotificationCenter defaultCenter] removeObserver:self name:@"tz" object:nil];
    }
    
    //发送通知
    - (void)buttonAction:(UIButton *)sender {
        // B传到A,反向传值
        [[NSNotificationCenter defaultCenter] postNotificationName:@"B2A" object:nil userInfo:@{@"key":self.bTextField.text}];
    
        [self.navigationController popToRootViewControllerAnimated:YES];
    
    }
    
    @end
    
  6. 单例传值
    用法:正向传值
    需求:当A-push到B时,B中有一个Label需要显示从A中的一个TextField输入的内容,这时我们需要用到正向传值。

    用法:反向传值:
    需求:A-push到B,当B消失的时候,A中有一个Label需要显示从B中的一个TextField输入的内容,这时我们需要用到反向传值。

    我们在此将两种传值情况写到一个Demo中,所以将上述Label换为Textfield即可,如下:

    A控制器.m文件:

    #import "A_ViewController.h"
    #import "B_ViewController.h"
    #import "DanLi.h"
    
    @interface A_ViewController ()
    
    @property (nonatomic, strong) UITextField *aTextField;
    
    @end
    
    @implementation A_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    
        self.title = @"A";
        self.view.backgroundColor = [UIColor whiteColor];
        self.aTextField = [[UITextField alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        self.aTextField.layer.borderColor = [UIColor grayColor].CGColor;
        self.aTextField.layer.borderWidth = 1;
        [self.view addSubview:self.aTextField];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"传到B" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
    }
    
    - (void)viewWillAppear:(BOOL)animated
    {
        // 单例 传值 B传到A (可以双向传值)
        DanLi *danli = [[DanLi alloc] init];
    
        self.aTextField.text = danli.value;
    }
    
    - (void)buttonAction:(UIButton *)sender {
    
        // 单例 传值 A传到B (可以双向传值)
        DanLi *danli = [DanLi sharedDanLi];
        danli.value = self.aTextField.text;
    
        B_ViewController *bViewController = [[B_ViewController alloc] init];
    
        [self.navigationController pushViewController:bViewController animated:YES];
    
    }
    

    B控制器.m文件:

    #import "B_ViewController.h"
    #import "DanLi.h"
    
    @interface B_ViewController ()
    
    @property (nonatomic, strong) UITextField *bTextField;
    
    @end
    
    @implementation B_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"B";
        self.view.backgroundColor = [UIColor whiteColor];
    
        self.view.backgroundColor = [UIColor whiteColor];
        self.bTextField = [[UITextField alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        self.bTextField.layer.borderColor = [UIColor grayColor].CGColor;
        self.bTextField.layer.borderWidth = 1;
        [self.view addSubview:self.bTextField];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"传值A" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
        self.bTextField.text = [DanLi sharedDanLi].value;
    }
    
    - (void)buttonAction:(UIButton *)sender {
        //B传给A
        [DanLi sharedDanLi].value = self.bTextField.text;
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    
    @end
    

    单例类.h文件:

    #import <Foundation/Foundation.h>
    
    @interface DanLi : NSObject
    
    //创建一个单例//如果在单线程里可以用nonatomic,如果在多线程里一定要用atomic,保证是只有一个在调用,不然在多线程里面如果多个方法调用修改单例类里的属性时会冲突
    @property (atomic, copy) NSString *value;
    
    + (DanLi *)sharedDanLi;
    
    @end
    

    单例类.m文件:

    #import "DanLi.h"
    
    static DanLi *danli = nil;
    
    @implementation DanLi
    
    //实现方法,判断是否为空,是就创建一个全局实例给它
    + (DanLi *)sharedDanLi {
    
        if (danli == nil) {
            danli = [[DanLi alloc] init];
        }
        return danli;
    }
    
    //避免alloc/new创建新的实例变量--->增加一个互斥锁
    + (id)allocWithZone:(struct _NSZone *)zone {
    
        @synchronized(self) {
            if (danli == nil) {
                danli = [super allocWithZone:zone];
            }
        }
        return danli;
    }
    
    //避免copy,需要实现NSCopying协议
    - (id)copyWithZone:(NSZone *)zone {
        return self;
    }
    
    @end
    
  7. KVC传值
    用法:正向传值
    需求:当A-push到B时,B中有一个Label需要显示从A中的一个TextField输入的内容,这时我们需要用到正向传值。

    A控制器.m文件:

    #import "A_ViewController.h"
    #import "B_ViewController.h"
    
    @interface A_ViewController ()
    
    @property (nonatomic, strong) UITextField *aTextField;
    
    @end
    
    @implementation A_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        self.title = @"A";
        self.view.backgroundColor = [UIColor whiteColor];
        self.aTextField = [[UITextField alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        self.aTextField.layer.borderColor = [UIColor grayColor].CGColor;
        self.aTextField.layer.borderWidth = 1;
        [self.view addSubview:self.aTextField];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"传到B" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    }
    
    - (void)buttonAction:(UIButton *)sender {
    
        B_ViewController *bViewController = [[B_ViewController alloc] init];
    
        /**
            KVC 传值:这里只能传A传到B (因为 B在A页面提前初始化)
            B 有个属性 string
            用B对象 给B属性赋值(回顾下OC中KVC赋值 就理解了)
    
            这里forkey 一定要和B 属性名字一致 (也可以用@"_string")因为是属性
         */
    
        // 给B属性string  赋值
        [bViewController setValue:self.aTextField.text forKey:@"string"];
    
        [self.navigationController pushViewController:bViewController animated:YES];
    }
    
    @end
    

    B控制器.h文件:

    #import <UIKit/UIKit.h>
    
    @interface B_ViewController : UIViewController
    
    @property (nonatomic, copy) NSString *string;
    
    @end
    

    B控制器.m文件:

    #import "B_ViewController.h"
    
    @interface B_ViewController ()
    
    @end
    
    @implementation B_ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.title = @"B";
        self.view.backgroundColor = [UIColor whiteColor];
    
        self.view.backgroundColor = [UIColor whiteColor];
        UILabel *bLabel = [[UILabel alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 200, 100, 30)];
    
        bLabel.layer.borderColor = [UIColor grayColor].CGColor;
        bLabel.layer.borderWidth = 1;
        [self.view addSubview:bLabel];
    
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2-50, 280, 100, 30);
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitle:@"传值A" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
        // KVC 接收值
        bLabel.text = self.string;
    }
    
    - (void)buttonAction:(UIButton *)sender {
    
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    
    @end
    

好了,到此已经基本上介绍完页面传值了,相信你对页面传值已经有一定理解了吧,快去实践吧!

iOS用AFN上传图片到服务器

1.单张图片上传

//上传图片(单张)
+(void)uploadPhotoAndController:(UIViewController *)controller WithSize:(CGSize)size Image:(UIImage*)image AndFinish:(void (^)(NSDictionary *, NSError *))finish
{
    //加载提示菊花
    MBProgressHUD *hud;
    if(controller){
        hud = [MBProgressHUD showHUDAddedTo:controller.view animated:YES];
        hud.label.text = NSLocalizedString(@"加载中...", @"HUD loading title");
    }

    //1. 存放图片的服务器地址,这里我用的宏定义
    NSString * url = [NSString stringWithFormat:@"%@%@",Hx_Main_heard_API,IMAGE_UPLOAD_URL_API];

    //2. 利用时间戳当做图片名字
       NSDateFormatter *formatter = [[NSDateFormatter alloc] init];  
    formatter.dateFormat = @"yyyyMMddHHmmss";  
    NSString *imageName = [formatter stringFromDate:[NSDate date]];  
    NSString *fileName = [NSString stringWithFormat:@"%@.jpg",imageName];

    //3. 图片二进制文件
    NSData *imageData = UIImageJPEGRepresentation(image, 0.7f);
    NSLog(@"upload image size: %ld k", (long)(imageData.length / 1024));

    //4. 发起网络请求
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    manager.requestSerializer = [AFHTTPRequestSerializer serializer];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    [manager POST:url parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        // 上传图片,以文件流的格式,这里注意:name是指服务器端的文件夹名字
        [formData appendPartWithFileData:imageData name:@"file" fileName:fileName mimeType:@"image/jpeg"];
    } success:^(AFHTTPRequestOperation *operation, id responseObject) {
        //上传成功时的回调
        [hud hideAnimated:YES];
        NSLog(@"%@",responseObject);
        finish(responseObject,nil);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        //失败时的回调
        [hud hideAnimated:YES];
        finish(nil,error);
    }];
}

2.多张图片上传

// 上传图片(多张)
+(void)uploadPhotoAndController:(UIViewController *)controller WithSize:(CGSize)size Image:(UIImage*)image AndFinish:(void (^)(NSDictionary *, NSError *))finish
{
    //加载提示菊花
    MBProgressHUD *hud;
    if(controller){
        hud = [MBProgressHUD showHUDAddedTo:controller.view animated:YES];
        hud.label.text = NSLocalizedString(@"加载中...", @"HUD loading title");
    }

    //1. 存放图片的服务器地址,这里我用的宏定义
    NSString * url = [NSString stringWithFormat:@"%@%@",Hx_Main_heard_API,IMAGE_UPLOAD_URL_API];

    //2. 发起网络请求
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    manager.requestSerializer = [AFHTTPRequestSerializer serializer];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];    
    [manager POST:url parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
    {
        // 上传多张图片
        for(NSInteger i = 0; i < self.imageDataArray.count; i++)
        {
            //取出单张图片二进制数据
            NSData * imageData = self.imageDataArray[i];

            // 上传的参数名,在服务器端保存文件的文件夹名
            NSString * Name = [NSString stringWithFormat:@"%@%ld", Image_Name, i+1];
            // 上传filename
            NSString * fileName = [NSString stringWithFormat:@"%@.jpg", Name];

            [formData appendPartWithFileData:imageData name:Name fileName:fileName mimeType:@"image/jpeg"];
        }
    }
    success:^(AFHTTPRequestOperation *operation, id responseObject)
     {
         //上传成功时的回调
        [hud hideAnimated:YES];
        NSLog(@"%@",responseObject);
        finish(responseObject,nil);           
     }
     failure:^(AFHTTPRequestOperation *operation, NSError *error)
     {
         //失败时的回调
        [hud hideAnimated:YES];
        finish(nil,error);
     }];
}

PS:上传图片前,必须先压缩图片,不然图片过大,可能会导致上传失败!

UIImagePickerController获取图片(拍照、相册、图库)详解

iOS 图片来源有三种方法:

typedef NS_ENUM(NSInteger, UIImagePickerControllerSourceType) {
    UIImagePickerControllerSourceTypePhotoLibrary,    //1.从图库中选择
    UIImagePickerControllerSourceTypeCamera,          //2.直接调用摄像头拍照
    UIImagePickerControllerSourceTypeSavedPhotosAlbum //3.从相册中选择
} __TVOS_PROHIBITED;

UIImagePickerController是系统提供的用来获取图片和视频的接口,用UIImagePickerController类来获取图片视频,大体分为以下几个步骤:

1. 实例化UIImagePickerController
2. 设置UIImagePickerController数据来源类型
3. 设置代理,遵循UIImagePickerControllerDelegate,UINavigationControllerDelegate协议
4. 实现代理方法接收选取图片并做处理

在代理中获取我们选中的图片,UIImagePickerControllerDelegate代理中一共三个方法,其中一个3.0已经废弃了,只剩下两个我们需要用的。

//1.当用户选取完成后调用;
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info;

//2.当用户取消选取时调用;
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker;

在这里,我们主要使用第一个代理方法,在选取图片完成后调用,选取的信息都在info中,info 是一个字典。

// 代理方法,获取图片
// 选取的信息都在info中,info 是一个字典。
/**
// info dictionary keys
UIKIT_EXTERN NSString *const UIImagePickerControllerMediaType __TVOS_PROHIBITED;//指定用户选择的媒体类型
UIKIT_EXTERN NSString *const UIImagePickerControllerOriginalImage __TVOS_PROHIBITED;//原始图片
UIKIT_EXTERN NSString *const UIImagePickerControllerEditedImage __TVOS_PROHIBITED;//修改后的图片
UIKIT_EXTERN NSString *const UIImagePickerControllerCropRect __TVOS_PROHIBITED;//裁剪尺寸
UIKIT_EXTERN NSString *const UIImagePickerControllerMediaURL __TVOS_PROHIBITED;//媒体的URL
UIKIT_EXTERN NSString *const UIImagePickerControllerReferenceURL        NS_AVAILABLE_IOS(4_1) __TVOS_PROHIBITED;//原件的URL
UIKIT_EXTERN NSString *const UIImagePickerControllerMediaMetadata       NS_AVAILABLE_IOS(4_1) __TVOS_PROHIBITED;//如果是拍照的照片,则需要手动保存到本地,系统不会自动保存拍照成功后的照片

下面是具体的代码,只写了核心的部分,当你需要获取系统图片时,执行- (void)startGetPhoto;此方法即可。

//点击更换头像时开始执行此方法
- (void)startGetPhoto
{
    self.actionSheet = [[UIActionSheet alloc] initWithTitle:nil
                                                   delegate:self
                                          cancelButtonTitle:@"取消"
                                     destructiveButtonTitle:nil
                                          otherButtonTitles:@"相册", @"拍照", nil];
    self.actionSheet.tag = ActionSheetTagAddPhoto;
    [self.actionSheet showInView:self.view];
}

#pragma mark -
#pragma mark UIActionSheetDelegate Call Back Implementation

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
       if (0 == buttonIndex)
    {
        //打开本地相册
        [self localPhoto];
    }
    else if(1 == buttonIndex)
    {
        // 开始拍照
        [self takePhoto];
    }

}

#pragma mark -
#pragma mark UIImagePickerControllerDelegate Call Back Implementation

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    NSString *type = [info objectForKey:UIImagePickerControllerMediaType];

    //当选择的类型是图片
    if ([type isEqualToString:@"public.image"])
    {
        NSString *key = nil;

        if (picker.allowsEditing)
        {
            key = UIImagePickerControllerEditedImage;
        }
        else
        {
            key = UIImagePickerControllerOriginalImage;
        }
        //获取图片
        UIImage *image = [info objectForKey:key];

        if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
            // 固定方向
            image = [image fixOrientation];//这个方法是UIImage+Extras.h中方法
            //压缩图片质量
            image = [self reduceImage:image percent:0.1];
            CGSize imageSize = image.size;
            imageSize.height = 320;
            imageSize.width = 320;
            //压缩图片尺寸
            image = [self imageWithImageSimple:image scaledToSize:imageSize];
        }
        //上传到服务器
        //[self doAddPhoto:image];
        //关闭相册界面
        [picker dismissViewControllerAnimated:YES completion:^{

        }];
    }
}

// 开始拍照
-(void)takePhoto
{
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
    {
        UIImagePickerController *picker = [[UIImagePickerController alloc] init];
        picker.sourceType = UIImagePickerControllerSourceTypeCamera;
        picker.delegate = self;
        //设置拍照后的图片可被编辑
        picker.allowsEditing = YES;
        picker.sourceType = UIImagePickerControllerSourceTypeCamera;
        //先检查相机可用是否
        BOOL cameraIsAvailable = [self checkCamera];
        if (YES == cameraIsAvailable) {
            [self presentViewController:picker animated:YES completion:nil];
        }else {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"请在iPhone的“设置-隐私-相机”选项中,允许本应用程序访问你的相机。" delegate:self cancelButtonTitle:@"好,我知道了" otherButtonTitles:nil];
            [alert show];
        }

    }
}

// 打开本地相册
-(void)localPhoto
{    
    //本地相册不需要检查,因为UIImagePickerController会自动检查并提醒
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    picker.delegate = self;
    //设置选择后的图片可被编辑
    picker.allowsEditing = YES;
    [self presentViewController:picker animated:YES completion:nil];
}

    //检查相机是否可用
- (BOOL)checkCamera
{
    NSString *mediaType = AVMediaTypeVideo;
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
    if(AVAuthorizationStatusRestricted == authStatus ||
       AVAuthorizationStatusDenied == authStatus)
    {
        //相机不可用
        return NO;
    }
    //相机可用
    return YES;
}

//压缩图片质量
-(UIImage *)reduceImage:(UIImage *)image percent:(float)percent
{
    NSData *imageData = UIImageJPEGRepresentation(image, percent);
    UIImage *newImage = [UIImage imageWithData:imageData];
    return newImage;
}
//压缩图片尺寸
- (UIImage*)imageWithImageSimple:(UIImage*)image scaledToSize:(CGSize)newSize
{
    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

UIImagePickerController显示中文界面

iOS开发中,我们经常遇到获取拍照、相册中图片的功能,就必然少不了UIImagePickerController,但是我们发现当我们使用它的时候,它的页面是英文的,看着很别扭,国人还是比较喜欢看中文界面,下面来看看我们怎么把它变成中文界面的吧!

只需下面两步就可以了:

  1. Project–>Info–>Localizations 添加 Chinese

Mou icon

  1. Target–>Info–>Localization native development region 值修改为 China

Mou icon

科普一下:以前xcode3生成的项目,修改Target–>Info–>Localization native development region 的值为China就能显示中文;Xcode4以后修改Target–>Info–>Localization native development region值为China还不够,同时还需要设置Project–>info–>Localizations Language添加Chinese才行。

动态计算UITableViewCell高度

在iOS开发中,我们少不了和UITableview打交道,因为UITableview也是UIKit中最复杂的一个控件了。在使用UITableview的过程中,UITableviewCell也是必不可少的,页面列表形式的展示可谓是各种各样,相信不少童鞋们也曾为复杂的页面布局困惑过,其中比较难的也就数cell的高度自适应了,也就是说cell的高度是根据内容来动态计算的。

不适用Autolayout的时候,计算cell的高度:

//返回cell的的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    PhotoInfo *photoInfo = [self.dataArr objectAtIndex:indexPath.row];
    [self heightForRowWithModel:photoInfo];
}

//动态计算cell的高度 
- (CGFloat)heightForRowWithModel:(PhotoInfo *)photoInfo 
{ 
    //这里只写了label的计算
      //文本的高度 
    CGSize texSize = [self labelAutoCalculateRectWith:photoInfo.instruction FontSize:15 MaxSize:CGSizeMake(200,1000)];
    //3.返回cell 的总高度 
    return 44 + textSize.height;
}  

/*根据传过来的文字内容、字体大小、宽度和最大尺寸动态计算文字所占用的size
              * text 文本内容 
              * fontSize 字体大小
              * maxSize  size(宽度,1000)
              * return  size (计算的size)
              */
- (CGSize)labelAutoCalculateRectWith:(NSString*)text FontSize:(CGFloat)fontSize MaxSize:(CGSize)maxSize
{
    NSMutableParagraphStyle* paragraphStyle = [[NSMutableParagraphStyle alloc]init];
   paragraphStyle.lineBreakMode=NSLineBreakByWordWrapping;
    NSDictionary* attributes =@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize],NSParagraphStyleAttributeName:paragraphStyle.copy};
    CGSize labelSize;
      //如果是IOS6.0
    if (![text respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]){
        labelSize = [text sizeWithFont:[UIFont systemFontOfSize:fontSize] constrainedToSize:maxSize lineBreakMode:NSLineBreakByWordWrapping];
    }
    //如果系统为iOS7.0
    else
  {
          // iOS7中用以下方法替代过时的iOS6中的sizeWithFont:constrainedToSize:lineBreakMode:方法
        labelSize = [text boundingRectWithSize: maxSize
                                       options: NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading|NSStringDrawingTruncatesLastVisibleLine
                                    attributes:attributes
                                       context:nil].size;
    }
    labelSize.height=ceil(labelSize.height);    
    labelSize.width=ceil(labelSize.width);
    return labelSize;
}

使用Autolayout,- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize这个方法就能搞定。不过,首先要在Xib上布局cell。

Mou icon

//返回cell高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    SystemMSGTableViewCell *cell = self.cell;
    SystemmsgInfo *data = self.dataArr[indexPath.row];
    CGFloat height = [cell heightForCell:data];
    return height;
} 

//动态计算cell的高度
- (CGFloat)heightForCell:(SystemmsgInfo *)data
{
    self.widthLabel.constant = ScreenWidth - 40;
    self.contentLabel.text = data.promotionInfo;
    CGSize size = [self.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    NSLog(@"h=%f", size.height + 1);
    return 1  + size.height;
}

效果图:

Mou icon

[svn]出现folder_is_already_under_version_control问题的解决办法

今天在提交项目时添加一个文件夹(folderName),结果svn出现了:Folder(文件夹)is already under version control这样的警告信息,并且怎么也提交不上。刚遇到此问题的时候感觉很奇怪,自己并没有在svn上添加这个目录(folderName),这里却提醒此目录(folderName)已经有version。而且svn上该目录状态也是?状态。经过查阅资料后才明白,原因是:我所添加的这个文件夹是从另一个项目中拷贝过来的,而且这个项目也是在svn上保存的,这样就导致我所提交的文件或目录是其他svn的东西,也就是说下面有.svn的目录,要解决此问题,删除要提交目录下的所有.svn文件即可,记住是该目录下所有.svn文件,注意递归子目录。

这里给出三种解决方式:其中前两种方法是递归删除该目录以及子目录下下所有.svn文件;第三种是本人用的比较笨的方法:也就是新建一个文件夹,然后将我们所需要的文件夹下的文件选中拷贝一份(记住不要拷贝目标文件夹,只拷贝里面需要的文件即可),最后将拷贝的文件放到新建的文件夹下,然后导入工程,避免有旧的.svn文件存在。

方法一:

打开终端,cd到你新增加的那个目录,然后用下面的命令

find . -mindepth 2 -name '.svn' -exec rm -rf '{}' \;
说明: -exec之后的rm -rf是命令以及参数,{}就是find的命令找到的结果集,\; 也是需要输入的哦

方法二:

同样是在终端里,cd到你新增加的那个目录,然后用下面的命令

find . -type d -name “.svn”|xargs rm -rf

方法三:

见上描述,本人觉得此方法是比较笨的方法,若有童鞋对命令行比较熟悉,可以采用以上高大上的方式,若像我一样对命令行了解不多,可以采用此方法,毕竟比较实用,哈哈!