UI基础

作者: 恒筠 | 来源:发表于2018-03-04 21:21 被阅读0次

    第一节

    1.UI控件中拖线属性或方法常见错误

    经典的错误
       1. 错误一
        描述:
          reason: '[<MainViewController 0x7ffebbc1a880> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key testLabel.'
        原因: 有多余的连线
        解决: 删除多余的连线
     
       2.错误二
        描述:
          reason: '-[MainViewController clickBtn:]: unrecognized selector sent to instance 0x7feb69418640'
        原因:找不到对应的方法
        解决:1.添加对应的方法  2.删除多余的连线
    

    2.UIView的常见属性

    • (void)addSubview:(UIView *)view;

      • 添加一个子控件view
    • (void)removeFromSuperview;

      • 将自己从父控件中移除
    • (UIView *)viewWithTag:(NSInteger)tag;

      • 根据一个tag标识找出对应的控件(一般都是子控件)
    • @property(nonatomic) CGRect frame;

      • 控件矩形框在父控件中的位置和尺寸(以父控件的左上角为坐标原点)
    • @property(nonatomic) CGRect bounds;

      • 控件矩形框的位置和尺寸(以自己左上角为坐标原点,所以bounds的x、y一般为0)
    • @property(nonatomic) CGPoint center;

      • 控件中点的位置(以父控件的左上角为坐标原点)

    第二节

    1.UIImageView的frame的设置

     // 设置frame的方式
        // 方式一
          UIImageView *imageView = [[UIImageView alloc] init];
          imageView.image = [UIImage imageNamed:@"1"];
         
    //    imageView.frame = CGRectMake(100, 100, 267, 400);
    //    imageView.frame = (CGRect){{100, 100},{267, 400}};
        */
        
        // 方式二
        /*
        UIImageView *imageView = [[UIImageView alloc] init];
        // 创建一个UIImage对象
        UIImage *image = [UIImage imageNamed:@"1"];
        // 设置frame
        imageView.frame = CGRectMake(100, 10, image.size.width, image.size.height);
        // 设置图片
        imageView.image = image;
         */
        
        // 方式三
        /*
        // 创建一个UIImage对象
        UIImage *image = [UIImage imageNamed:@"1"];
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 10, image.size.width, image.size.height)];
        imageView.image = image;
         */
        
        // 方式四
        
        // 创建一个UIimageview对象
        // 注意: initWithImage 默认就有尺寸--->图片的尺寸
        UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1"]];
        
        // 改变位置
    //    imageView.center = CGPointMake(200, 150);
        
        imageView.center = CGPointMake(self.view.frame.size.width * 0.5, self.view.frame.size.height * 0.5);
    
    

    2.控件的创建方式

    • 一个控件有2种创建方式

      • 通过代码创建
      • 初始化时一定会调用initWithFrame:方法
    • 通过xib\storyboard创建

      • 初始化时不会调用initWithFrame:方法,只会调用initWithCoder:方法
      • 初始化完毕后会调用awakeFromNib方法

    注意:
    有时候希望在控件初始化时做一些初始化操作,比如添加子控件、设置基本属性
    这时需要根据控件的创建方式,来选择在initWithFrame:、initWithCoder:、awakeFromNib的哪个方法中操作

    3.xib的加载

    方法1
    NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"xib文件名" owner:nil options:nil]
    
    方法2
    UINib *nib = [UINib nibWithNibName:@"xib文件名" bundle:nil];
    NSArray *views = [nib instantiateWithOwner:nil options:nil];
    

    4.加载图片的方式

    1. imageNamed:与
    2. imageWithContentsOfFile:的区别
    • 加载Assets.xcassets这里面的图片:

    • 1> 打包后变成Assets.car
      
    • 2> 拿不到路径
      
    • 3> 只能通过imageNamed:来加载图片
      
    • 4> 不能通过imageWithContentsOfFile:来加载图片
      
    • 放到项目中的图片:

    • 1> 可以拿到路径
      
    • 2> 能通过imageNamed:来加载图片
      
    • 3> 也能通过imageWithContentsOfFile:来加载图片
      
    图片的两种加载方式:
    1> imageNamed:
      a. 就算指向它的指针被销毁,该资源也不会被从内存中干掉
      b. 放到Assets.xcassets的图片,默认就有缓存
      c. 使用场景:图片经常被使用
    
    2> imageWithContentsOfFile:
      a. 指向它的指针被销毁,该资源会被从内存中干掉
      b. 放到项目中的图片就没有缓存
      c. 使用场景:不经常用,大批量的图片
    

    5.Xcode插件大全

    第三节

    1.九宫格

    • 处在同一列的x值是一样的

    • 处在同一行的y值是一样的

    • 在九宫格中计算每一个小格子的位置

    • x值 = (小格子的宽 + 小格子之间的水平间距)*(格子的下标%格子的总列数)

    • y值 = (小格子的高 + 小格子之间的垂直间距)*(格子的下标/格子的总列数)

    第四节

    1.懒加载

    1.作用:
    1>用到的时候再加载
    2>全局只会被加载一次
    3>全局都可以使用

    过程:
    1.重写成员变量的get方法
    2.在get方法中判断:
    1>如果为空,加载数据
    2>如果不为空,就直接返回数据

    第五节

    1.自定义控件与模型

    • 加载自定义控件分为两种:一种是代码加载自定义控件
    * 首先在自定义控件的.m文件中重写initwithframe方法,在这个方法中创建控件
    
    * 然后再laysubview方法中给控件设置尺寸
    
    * 在.h文件中设置一个模型属性,然后在.m文件中充血模型属性的set方法,把传递进来的模型属性的值设置给对应控件
    

    为自定义控件充血init 和 类工厂方法,

    • 宁外一种加载自定义控件的方法的事通过xib加载

      • 首先创建xib的文件,布局xib,关联xib对应的class

      • 在xib对应的class类的.h文件中,设置模型属性

      • 在.m文件中充血模型的set方法

      • 在.m属性中拉线给xib控件赋值

    2.自定义按钮

    注意: 在按钮外面改的尺寸,按钮的内部都会覆盖掉

        /*
        button.titleLabel.frame = CGRectMake(0, 0, 100, 70);
        button.imageView.frame = CGRectMake(100, 0, 70, 70);
         */
    

    正确的做法

    [button titleRectForContentRect:CGRectMake(0, 0, 100, 70)];
    [button imageRectForContentRect:CGRectMake(100, 0, 70, 70)];
    
    
    

    如果需要改变按钮控件内部的图片和label的frame的话又两种方法

    一个是重写按钮内部的layoutsubview方法
    另外一个是重写按钮内部的

    • (CGRect)titleRectForContentRect:(CGRect)contentRect

    • (CGRect)imageRectForContentRect:(CGRect)contentRect

    3.图片的拉伸问题

    
      UIImage *resizableImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(imageHeight * 0.5, imageWidth * 0.5, imageHeight * 0.5 -1, imageWidth * 0.5 - 1)];
      
    

    另外的一个方法

    //    UIImage *resizableImage = [image stretchableImageWithLeftCapWidth:imageWidth * 0.5 topCapHeight:imageHeight * 0.5];
    
    

    4.KVC

    >1.利用KVC进行简单赋值

    在简单赋值过程中会进行自动类型转换比如

    [person setValue:@"19" forKeyPath:@"money"]; 
    NSLog(@"%@-----%.2f", person.name, person.money)
    

    打印结果整形转成浮点型

    >2.KVC综合赋值

     forKey和forKeyPath
     1>forKeyPath 包含了所有 forKey 的功能
     2>forKeyPath 进行内部的点语法,层层访问内部的属性
     3>注意: key值一定要在属性中找到
    

    >3.利用KVC修改类的私有成员变量

    利用KVC修改类的私有成员变量

    4.字典转模型

    作用: 字典转模型
    开发中是不建议使用setValuesForKeysWithDictionary:
    1> 字典中的key必须在模型的属性中找到
    2> 如果模型中带有模型,setValuesForKeysWithDictionary不好使
    应用场景: 简单的字典转模型 ---> 框架 (MJExtention)

    5.取值

    6.把模型转成字典

       NSDictionary *dict = [person dictionaryWithValuesForKeys:@[@"name", @"money"]];
    

    7.取出数组中所有模型的某个属性值

            XMGPerson *person1 = [[XMGPerson alloc] init];
            person1.name = @"zhangsan";
            person1.money = 12.99;
            
            XMGPerson *person2 = [[XMGPerson alloc] init];
            person2.name = @"zhangsi";
            person2.money = 22.99;
            
            XMGPerson *person3 = [[XMGPerson alloc] init];
            person3.name = @"wangwu";
            person3.money = 122.99;
            
            NSArray *allPersons = @[person1, person2, person3];
            NSArray *allPersonName = [allPersons valueForKeyPath:@"name"];
            
            NSLog(@"%@", allPersonName);
    

    5KVO

    KVO: Key Value Observing (键值监听)--->当某个对象的属性值发生改变的时候(用KVO监听)

        /*
         作用:给对象绑定一个监听器(观察者)
         - Observer 观察者
         - KeyPath 要监听的属性
         - options 选项(方法方法中拿到属性值)
         */
        [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
        
        
        person.name = @"ls";
        
        person.name = @"ww";
        
    
        
        // 移除监听
        [person removeObserver:self forKeyPath:@"name"];
    

    注意增加监听的时候记得移除监听,就好像添加通知要移除通知一样

    增加监听以后可以在observeValueForKeyPath这个方法中监听到属性值的改变

    第六节

    1.监听scrollView各种行为的3大步骤(比如让控制 器监听scrollView的行为)

    • 设置scrollView的delegate(代理)为控制器对象
    • 控制器要遵守UIScrollViewDelegate协议
    • 控制器要实现UIScrollViewDelegate协议里面的代理方法
    scrollView.delegate = 控制器;
    
      
    @interface 控制器 () <UIScrollViewDelegate> @end
     
     
    #pragma mark - <UIScrollViewDelegate> 代理 法
    {
    NSLog(@"scrollViewDidScroll-滚动"); }
    

    2.代理使用的一般规律

    • 作用:用来监听控件的某些行为
    • 代理:是控制器对象
    • 代理:是id类型,并且是弱指针(weak)
    • 代理协议的格式:控件类名+Delegate,比如UIScrollViewDelegate、 UITableViewDelegate
    • 代理方法:方法名一般是控件名开头,比如UIScrollView的代理方法一般以scrollView开 头

    3.如何监听控件的行为

    • 通过addTarget:

      • 只有继承自UIControl的控件,才有这个功能 UIControlEventTouchUpInside : 点击事件(UIButton)

      • UIControlEventValueChanged : 值改变事件(UISwitch、UISegmentControl、 UISlider)
        UIControlEventEditingChanged : 文字改变事件(UITextField)

    • 通过delegate 只有拥有delegate属性的控件,才有这个功能

    4.NSTimer的使用

    • 开启定时器
     @property (nonatomic, weak) NSTimer *timer;
    [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
     // 返回 个 动开始执 任务的定时器
     
     self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self
     
    
    // NSDefaultRunLoopMode(默认): 同一时间只能执行一个任务
    // NSRunLoopCommonModes(公用): 可以分配一定的时间执行其他任务
    // 作用:修改timer在runLoop中的模式为NSRunLoopCommonModes
    // 目的:不管主线程在做什么操作,都会分配一定的时间处理定时器
    
    • 关闭定时器
      [self.timer invalidate];
    

    5.UIScrollView

    1.基本使用

    • 介绍
    • 设置内容尺寸(contentSize)
    • 不能滚动的原因

    2.常见属性

    • 是否有弹簧效果
    • 是否总是有弹簧效果
      • 作用:下拉刷新,上拉加载
    • 是否显示滚动条
      • 滚动条的样式
    • 滚动条是imageView
    • 注意点:不要通过索引去subViews这个数组中去访问scrollView的子控件

    3.偏移量和内边距

    4.监听scrollView的各种行为

    • 代理的介绍
      • 代码创建scrollView和storyboard创建的区别
      • 代码创建要等到真正要显示的时候才会有滚动条

    如何监听scrollView已经停止滚动 有2种情况
    第一种手松开,scrollView就停止滚动 第二种,用户停止拖拽,但scrollView由于惯性继续滚动,并且减速

    5.内容缩放

    • 通过代理告知哪一个控件需要缩放
    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;
    
    • 设置缩放的比例
    * 设置minimumZoomScale 
    * 设置maximumZoomScale   
    
    • 监听缩放的过程

    跟缩放相关的其他代理方法
    即将开始缩放的时候调用

    • (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view

    正在缩放的时候调用

    • (void)scrollViewDidZoom:(UIScrollView *)scrollView
    • 禁止缩放的弹簧效果

    第七节

    1.Autolayout

    • Autolayout的2个核心概念

      • 约束:通过给控件添加约束,来决定控件的位置和尺寸
      • 参照:在添加约束时,是依照谁来添加(可以是父控件或者兄弟控件)
    • 代码实现Autolayout的注意点

    • 要先禁止autoresizing功能,设置view的下面属性为NO

    • view.translatesAutoresizingMaskIntoConstraints = NO;

    • 添加约束之前,一定要保证相关控件都已经在各自的父控件上

    • 不用再给view设置frame

    • 一个NSLayoutConstraint对象就代表一个约束

    • 创建约束对象的常用方法

    +(id)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 :乘数
    c :常量
    
    

    [图片上传失败...(image-cbf8ee-1520169654402)]

    在添加时要注意目标view需要遵循以下规则:

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

    [图片上传失败...(image-42483c-1520169654402)]

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

    [图片上传失败...(image-dea5d5-1520169654402)]

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

    [图片上传失败...(image-f2d463-1520169654402)]

    • 在修改了约束之后,只要执行下面代码,就能做动画效果
    [UIView animateWithDuration:1.0 animations:^{
        [添加了约束的view的父控件 layoutIfNeeded];
    }];
    
    • 补充:
      • autolayout中baselines的选项可以为label和button设置下方对齐

    2.VFL语言实现autolayout

    使用VFL来创建约束数组
    + (NSArray *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views;
    format :VFL语句
    opts :约束类型
    metrics :VFL语句中用到的具体数值
    views :VFL语句中用到的控件
    
    创建一个字典(内部包含VFL语句中用到的控件)的快捷宏定义
    NSDictionaryOfVariableBindings(...)
    
    

    3.Masonry目前最流行的autolayout的第三方kuangjia

    默认情况下
    mas_equalTo有自动包装功能,比如自动将20包装为@20
    equalTo没有自动包装功能
    
    如果添加了下面的宏,那么mas_equalTo和equalTo就没有区别
    #define MAS_SHORTHAND_GLOBALS
    // 注意:这个宏一定要添加到#import "Masonry.h"前面
    
    默认情况下
    width是make对象的一个属性,用来添加宽度约束用的,表示对宽度进行约束
    mas_width是一个属性值,用来当做equalTo的参数,表示某个控件的宽度属性
    
    如果添加了下面的宏,mas_width也可以写成width
    #define MAS_SHORTHAND
    
    mas_height、mas_centerX以此类推
    

    第八节

    1.���UITableView

    • 在tableview中,如果显示的内容没有撑满整个屏幕,可以通过在尾部设置tableview。viewforfoot的属性为一个空的view来达到撑满整个屏幕的效果,也可以改变tableview的样式为group

    • 在tableview中的cellforrowatindexpath空,���中谨记有if就要有else,因为table的cell都是循环引用的

    • UITableView的每一行都是一个UITableViewCell,通过dataSource的tableView:cellForRowAtIndexPath:方法来初始化每一行

    • UITableViewCell内部有个默认的子视图:contentView,contentView是UITableViewCell所显示内容的父视图,可显示一些辅助指示视图

    注意:在开发中等号左右两边的类型要是同一类型

    2.UITableViewCell

    UITableViewCell重用

    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // 1.定义一个cell的标识
          static NSString *ID = @”cell";
        
        // 2.从缓存池中取出cell
          UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
        
        // 3.如果缓存池中没有cell
          if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
        }
    

    注意:tableview和tableviewcell有一个共同的特点就是他们一创建出来就已经确定了样式,在接下去的代码中用访问属性的点语法也改不了他们的样式

    第九节

    1.在UITableview中自定义等高cell

    • 第一种使用纯代码实现(frame)

    新建一个继承自UITableViewCell的子类,比如XMGTgCell

    @interface XMGTgCell : UITableViewCell
    @end
    

    在XMGTgCell.m文件中

    • 重写-initWithStyle:reuseIdentifier:方法
      • 在这个方法中添加所有需要显示的子控件
      • 给子控件做一些初始化设置(设置字体、文字颜色等)
    /**
     *  在这个方法中添加所有的子控件
     */
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
    {
        if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
            // ......
        }
        return self;
    }
    
    • 重写-layoutSubviews方法
      • 一定要调用[super layoutSubviews]
      • 在这个方法中计算和设置所有子控件的frame
    /**
     *  在这个方法中计算所有子控件的frame
     */
    - (void)layoutSubviews
    {
        [super layoutSubviews];
    
        // ......
    }
    

    在XMGTgCell.h文件中提供一个模型属性,比如XMGTg模型

    @class XMGTg;
    
    @interface XMGTgCell : UITableViewCell
    /** 团购模型数据 */
    @property (nonatomic, strong) XMGTg *tg;
    @end
    

    在XMGTgCell.m中重写模型属性的set方法

    • 在set方法中给子控件设置模型数据
    - (void)setTg:(XMGTg *)tg
    {
        _tg = tg;
    
        // .......
    }
    

    在控制器中

    • 注册cell的类型
    [self.tableView registerClass:[XMGTgCell class] forCellReuseIdentifier:ID];
    
    • 给cell传递模型数据
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // 访问缓存池
        XMGTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
        // 设置数据(传递模型数据)
        cell.tg = self.tgs[indexPath.row];
    
        return cell;
    }
    

    2.在UITableview中自定义不登高的cell

    给模型增加frame数据

    • 所有子控件的frame
    • cell的高度(cellHeight)
    @interface XMGStatus : NSObject
    /**** 文字\图片数据 ****/
    // .....
    
    /**** frame数据 ****/
    /** 头像的frame */
    @property (nonatomic, assign) CGRect iconFrame;
    // .....
    /** cell的高度 */
    @property (nonatomic, assign) CGFloat cellHeight;
    @end
    
    • 重写模型cellHeight属性的get方法
    - (CGFloat)cellHeight
    {
        if (_cellHeight == 0) {
            // ... 计算所有子控件的frame、cell的高度
        }
        return _cellHeight;
    }
    

    在控制器中

    • 实现一个返回cell高度的代理方法
      • 在这个方法中返回indexPath位置对应cell的高度
    /**
     *  返回每一行cell的具体高度
     */
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        XMGStatus *status = self.statuses[indexPath.row];
        return status.cellHeight;
    }
    
    • 给cell传递模型数据
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // 访问缓存池
        XMGStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
        // 设置数据(传递模型数据)
        cell.status = self.statuses[indexPath.row];
    
        return cell;
    }
    

    新建一个继承自UITableViewCell的子类,比如XMGStatusCell

    @interface XMGStatusCell : UITableViewCell
    @end
    

    在XMGStatusCell.m文件中

    • 重写-initWithStyle:reuseIdentifier:方法
      • 在这个方法中添加所有可能需要显示的子控件
      • 给子控件做一些初始化设置(设置字体、文字颜色等)
    /**
     *  在这个方法中添加所有可能需要显示的子控件
     */
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
    {
        if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
            // ......
        }
        return self;
    }
    

    在XMGStatusCell.h文件中提供一个模型属性,比如XMGStatus模型

    @class XMGStatus;
    
    @interface XMGStatusCell : UITableViewCell
    /** 微博模型数据 */
    @property (nonatomic, strong) XMGStatus *status;
    @end
    

    在XMGStatusCell.m中重写模型属性的set方法

    • 在set方法中给子控件设置模型数据
    - (void)setStatus:(XMGStatus *)status
    {
        _status = status;
    
        // .......
    }
    

    重写-layoutSubviews方法

    • 一定要调用[super layoutSubviews]
    • 在这个方法中设置所有子控件的frame
    /**
     *  在这个方法中设置所有子控件的frame
     */
    - (void)layoutSubviews
    {
        [super layoutSubviews];
    
        // ......
    }
    




    3自定义不等高的cell 使用storyboard

    对比自定义等高cell,需要几个额外的步骤(iOS8开始才支持)

    • 添加子控件和contentView之间的间距约束
    • 设置tableViewCell的真实行高和估算行高
    // 告诉tableView所有cell的真实高度是自动计算(根据设置的约束来计算)
    self.tableView.rowHeight = UITableViewAutomaticDimension;
    // 告诉tableView所有cell的估算高度
    self.tableView.estimatedRowHeight = 44;
    

    如果要支持iOS8之前

    • 如果cell内部有自动换行的label,需要设置preferredMaxLayoutWidth属性
    - (void)awakeFromNib
    {
        // 手动设置文字的最大宽度(目的是:让label知道自己文字的最大宽度,进而能够计算出自己的frame)
        self.text_label.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20;
    }
    
    • 设置tableView的cell估算高度
    // 告诉tableView所有cell的估算高度(设置了估算高度,就可以减少tableView:heightForRowAtIndexPath:方法的调用次数)
    self.tableView.estimatedRowHeight = 200;
    
    • 在代理方法中计算cell的高度
    XMGStatusCell *cell;
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // 创建一个临时的cell(cell的作用:根据模型数据布局所有的子控件,进而计算出cell的高度)
        if (!cell) {
            cell = [tableView dequeueReusableCellWithIdentifier:ID];
        }
    
        // 设置模型数据
        cell.status = self.statuses[indexPath.row];
    
        return cell.height;
    }
    
    - (CGFloat)height
    {
        // 强制布局cell内部的所有子控件(label根据文字多少计算出自己最真实的尺寸)
        [self layoutIfNeeded];
    
        // 计算cell的高度
        if (self.status.picture) {
            return CGRectGetMaxY(self.pictureImageView.frame) + 10;
        } else {
            return CGRectGetMaxY(self.text_label.frame) + 10;
        }
    }
    

    第十节

    1.iOS面试相关

    2. 数据刷新

    • 添加数据
    • 删除数据
    • 更改数据

    3.全局刷新方法(最常用)

    [self.tableView reloadData];
    // 屏幕上的所有可视的cell都会刷新一遍
    

    4.局部刷新方法

    • 添加数据
    NSArray *indexPaths = @[
                            [NSIndexPath indexPathForRow:0 inSection:0],
                            [NSIndexPath indexPathForRow:1 inSection:0]
                            ];
    [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationRight];
    
    • 删除数据
    NSArray *indexPaths = @[
                            [NSIndexPath indexPathForRow:0 inSection:0],
                            [NSIndexPath indexPathForRow:1 inSection:0]
                            ];
    [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationMiddle];
    
    • 更新数据(没有添加和删除数据,仅仅是修改已经存在的数据)
    NSArray *indexPaths = @[
                            [NSIndexPath indexPathForRow:0 inSection:0],
                            [NSIndexPath indexPathForRow:1 inSection:0]
                            ];
    [self.tableView relaodRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationMiddle];
    

    5.左滑出现删除按钮

    • 需要实现tableView的代理方法
    /**
     *  只要实现了这个方法,左滑出现Delete按钮的功能就有了
     *  点击了“左滑出现的Delete按钮”会调用这个方法
     */
    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // 删除模型
        [self.wineArray removeObjectAtIndex:indexPath.row];
    
        // 刷新
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
    }
    
    /**
     *  修改Delete按钮文字为“删除”
     */
    - (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return @"删除";
    }
    

    6.左滑出现N个按钮

    • 需要实现tableView的代理方法
    /**
     *  只要实现了这个方法,左滑出现按钮的功能就有了
     (一旦左滑出现了N个按钮,tableView就进入了编辑模式, tableView.editing = YES)
     */
    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
    {
    
    }
    
    /**
     *  左滑cell时出现什么按钮
     */
    - (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewRowAction *action0 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"关注" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
            NSLog(@"点击了关注");
    
            // 收回左滑出现的按钮(退出编辑模式)
            tableView.editing = NO;
        }];
    
        UITableViewRowAction *action1 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
            [self.wineArray removeObjectAtIndex:indexPath.row];
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        }];
    
        return @[action1, action0];
    }
    

    7.进入编辑模式

    // self.tabelView.editing = YES;
    [self.tableView setEditing:YES animated:YES];
    // 默认情况下,进入编辑模式时,左边会出现一排红色的“减号”按钮
    

    8.在编辑模式中多选

    // 编辑模式的时候可以多选
    self.tableView.allowsMultipleSelectionDuringEditing = YES;
    // 进入编辑模式
    [self.tableView setEditing:YES animated:YES];
    
    // 获得选中的所有行
    self.tableView.indexPathsForSelectedRows;
    

    第十一节

    代理的使用步骤

    • 定义一份代理协议

      • 协议名字的格式一般是:类名 + Delegate
        • 比如UITableViewDelegate
      • 设计代理的细节
        • 一般都是@optional(让代理可以有选择性去实现一些代理方法)
        • 方法名一般都以类名开头
          • 比如- (void)scrollViewDidScroll:
        • 一般都需要将对象本身传出去
          • 比如tableView的代理方法都会把tableView本身传出去
      • 必须要遵守NSObject协议(基协议)
        • 比如@protocol XMGWineCellDelegate <NSObject>
    • 声明一个代理属性

      • 代理的类型格式:id<协议> delegate
    @property (nonatomic, weak) id<XMGWineCellDelegate> delegate;
    
    • 设置代理对象

    • 代理对象遵守协议,实现协议里面相应的方法

    • 当控件内部发生了一些事情,就可以调用代理的代理方法通知代理

      • 如果代理方法是@optional,那么需要判断方法是否有实现,直接调用可能会报错
    if ([self.delegate respondsToSelector:@selector(wineCellDidClickPlusButton:)]) {
        [self.delegate wineCellDidClickPlusButton:self];
    }
    

    iOS监听某些事件的方法

    • 通知(NSNotificationCenter\NSNotification)

      • 任何对象之间都可以传递消息
      • 使用范围
        • 1个对象可以发通知给多个对象
        • 1个对象可以接受多个对象发出的通知
      • 要求:必须得保证通知的名字在发出和监听时是一致的
    • KVO

      • 仅仅是能监听对象属性的改变(灵活度不如通知和代理)
    • 代理

      • 使用范围
        • 1个对象只能设置一个代理(假设这个对象只有1个代理属性)
        • 1个对象能成为多个对象的代理
    • 如何选择?

      • 代理通知规范
      • 建议使用代理多于通知,能使用代理尽量使用代理

    相关文章

      网友评论

          本文标题:UI基础

          本文链接:https://www.haomeiwen.com/subject/behxfftx.html