美文网首页
UIView的深入理解

UIView的深入理解

作者: 宙斯YY | 来源:发表于2018-05-11 11:18 被阅读107次

    一、自定义View需要继承UIView

    @interface ZSUIView : UIView
    

    注意的几点问题:

    1.initWithFrame

    init和initWithFrame都是UIView初始化方法,初始化UIView对象的时候可以通过这两种方式。(使用代码创建UIView)

    //第一种方式
    ZSUIView  *view=[[ZSUIView alloc]init];
    view.frame=CGRectMake(100, 100, 100, 100);
    //第二种方式
    ZSUIView  *view=[[ZSUIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
    

    init内部会调用initWithFrame,也就是无论第一种还是第二种方式都会调用initWithFrame方法,所以重写initWithFrame才能避免外部初始化UIView的局限性。

    自定义初始化方法以init开头,才会调用initWithFrame。

    -(instancetype)initWithData:(NSString *)data
    {
        if(self=[super init])
        {
        }
        return self;
    }
    

    如果用xib创建View,会先initWithCoder方法(加载时),再调用awakeFromNib方法(加载完)。

    2.layoutSubviews

    用来布局子View的Frame
    相比在初始化方法initWithFrame中设置子View的Frame有几点优势
    a.分离布局代码,初始化方法中只会在初始化设置一次,如果想再改变需要分别设置,麻烦。
    b.子View的布局可以跟随父View布局改变而改变。
    其中涉及到layoutSubviews的调用机制,
    addsubview的时候

    ZSUIView*view=[[ZSUIView alloc]init];
    [self.view addSubview:view];//ZSUIView中layoutSubviews被调用。
    
    @implementation ZSUIView
    -(void)layoutSubviews
    {
        NSLog(@"%@:%@",NSStringFromClass(self.class),NSStringFromSelector(_cmd));
        [super layoutSubviews];
        self.bgview.frame=CGRectMake(10, 10, self.frame.size.width/3, self.frame.size.height/3);
    }
    @end
    

    父View尺寸(不包括位置)改变的时候

    - (IBAction)clickTest:(id)sender {
        CGRect viewFrame=view.frame;
        //viewFrame.origin.x+=10;  //ZSUIView中layoutSubviews不会被调用。
        viewFrame.size.width+=10; //ZSUIView中layoutSubviews被调用。
        view.frame=viewFrame;
      }
    

    如果子View尺寸改变,父View的layoutSubviews同样也会被调用
    Xib创建的自定义View同样适用。

    所以,给我们布局提供的思路就是,子View的布局跟随父View布局而布局,如果父View布局改变,子View也不会太丑;做一些动态尺寸控件时候子View变化的布局写在layoutSubviews中。

    3.UITextField

    InPutView:默认键盘
    AccessoryInputView:默认无
    一个思路是继承UITextField,初始化的时候重写InPutView属性,比如改成PickerView,点击就弹出PickerView,也是自定义键盘的思路。
    AccessoryInputView用来做评论回复之类的功能。

    4.initWithFrame、initWithCoder、awakeFromNib

    通过存代码创建View,initWithFrame被调用
    通过xib,sb创建View,先调用initWithCoder,再调用awakeFromNib
    此时,initWithCoder中子控件还没有创建出来(解析文件开始调用),在awakeFromNib才创建出来。

    二、UIButton

    1.背景图片拉伸

    -(UIImage*)resizeImage
    {
        UIImage *image = self;
        // 设置端盖的值
        CGFloat top = image.size.height * 0.5;
        CGFloat left = image.size.width * 0.5;
        CGFloat bottom = image.size.height * 0.5;
        CGFloat right = image.size.width * 0.5;
        // 设置端盖的值
        UIEdgeInsets edgeInsets = UIEdgeInsetsMake(top, left, bottom, right);
        // 设置拉伸的模式
        UIImageResizingMode mode = UIImageResizingModeStretch;
        // 拉伸图片
        UIImage *newImage = [image resizableImageWithCapInsets:edgeInsets resizingMode:mode];
        return newImage;
    }
    @end
    

    2.调整按钮内部图片和文字的位置

        //默认图片文字左右结构,改变为右左结构
        CGRect iFrame=self.testBtn.imageView.frame;
        CGRect tFrame=self.testBtn.titleLabel.frame;
        iFrame.origin.x=CGRectGetMaxX(tFrame);
        self.testBtn.imageView.frame=iFrame;
        self.testBtn.titleLabel.frame=tFrame;
    

    三、UIScrollView

    1.contentOffset,contentInset

    contentOffset是内容相对于tableview-frame起始点的偏移量;header属于tableview内容的一部分;而contentInset不属于tableview内容的一部分。
    contentInset是指tableview内容的边距,除内容外还能额外看到的区域。
    (做自定义下拉加载悬停就是控制这个属性值)
    所以如果给tableview加一个header,默认contentOffset.y从0开始;
    如果给tableview加一个contentInset.top,默认contentOffset.y从-top开始,但是从top开始显示;
    有导航条的tableview,默认contentOffset.y=-navBarHeight,除非添加以下属性,保证从contentOffset.y从0开始。

    if (@available(iOS 11.0, *)) {
            tv.contentInsetAdjustmentBehavior=UIScrollViewContentInsetAdjustmentNever;
        } else {
            self.automaticallyAdjustsScrollViewInsets=NO;
        }
    

    有一些UIScrollView的contentOffset(0,0)但是还有外边框的样式UI,这样做比较符合逻辑。

    2.delegate方法

    -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    {
        //1->
        NSLog(@"scrollViewWillBeginDragging");
    }
    -(void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
    {
        //2->
        NSLog(@"scrollViewWillEndDragging");
    }
    -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
    {
        //3->decelerate为YES 4才会被调用
       //从交互上感受就是 如果用户拖拽之后scrollview有惯性滑动才会调用减速
       //如果拖拽之后就不动了那么就不产生减速效果,也不调用减速代理方法
        NSLog(@"scrollViewDidEndDragging:%d-%f",decelerate,scrollView.contentOffset.x);
    }
    -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
        //4.
        NSLog(@"scrollViewDidEndDecelerating:%f",scrollView.contentOffset.x);
    }
    
    -(UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView
    {
        //指定scrollview哪个控件进行缩放,同时指定缩放比例就可以完成缩放功能
        //self.scrollview.maximumZoomScale=2;
        //self.scrollview.minimumZoomScale=0.5;
        return nil;
    }
    

    3.scrollsToTop

    .h文件是这么描述的:
    当用户点击状态栏,滑动到顶部,也可以通过scrollViewShouldScrollToTop代理设置;
    默认YES;
    当在屏幕上有多个UIScrollView,scrollsToTop失效,所以tableview嵌套tableview的情况,就没有scrollsToTop功能,但是如果内部tableview.scrollsToTop=NO;外部tableview.scrollsToTop=YES;就可以生效。

    // When the user taps the status bar, the scroll view beneath the touch which is closest to the status bar will be scrolled to top, but only if its `scrollsToTop` property is YES, its delegate does not return NO from `-scrollViewShouldScrollToTop:`, and it is not already at the top.
    // On iPhone, we execute this gesture only if there's one on-screen scroll view with `scrollsToTop` == YES. If more than one is found, none will be scrolled.
    @property(nonatomic) BOOL  scrollsToTop __TVOS_PROHIBITED;          // default is YES.
    

    四、AutoLayout

    1.在xib或者sb中添加控件,默认contrain to margins是选中的,所以这就是为什么设置左边距0会有间距,取消该选中就可以了。

    2.UILabel包裹内容

    • 设置UILabel的位置
    • 不设置高度约束,宽度约束设置为<=

    3.约束优先级

    使用场景:
    三个连续相隔20pt的View,如果做到去掉中间的View,右侧的View靠近左侧View20pt。
    对右侧的View进行左侧View和中间View20pt的两个约束(当然会报错),只需要把左侧View20pt的约束优先级调整低就不会出错,而且实现该需求。

    4.修改约束

    把约束拖拽到控制器进行修改。

    //约束的改变本质也是改变view的frame
    self.grayviewheight.constant=100;
    //给改变约束添加动画的方式->
        [UIView animateWithDuration:2.0 animations:^{
      //强制self.view的子控件布局刷新
            [self.view layoutIfNeeded];
        }];
    

    效果相当于

    CGRect grayFrame=self.grayview.frame;
    grayFrame.size.width=100;
    [UIView animateWithDuration:2.0 animations:^{
    self.grayview.frame=grayFrame;
    }];
    

    5.Masonry

    如果你的控件是代码创建的,还需要添加约束,那么->masonry。

    • 给一个UIView添加约束,先添加该UIView,再添加约束。
    UIView * mview=[[UIView alloc]init];
    mview.backgroundColor=[UIColor orangeColor];
    [self.view addSubview:mview];
    [mview mas_makeConstraints:^(MASConstraintMaker *make) {}
    
    • 基本思路就是相对于x控件的偏移约束是x
    [mview mas_makeConstraints:^(MASConstraintMaker *make) {
            //1.0 mview左边相对于self.view的左边距离20pt,右边底边距离20,高度100
            make.left.equalTo(self.view.mas_left).offset(20);
            make.right.equalTo(self.view.mas_right).offset(-20);
            make.bottom.equalTo(self.view.mas_bottom).offset(-20);
            make.height.mas_equalTo(100);
            
            //1.1 左边相对于左边则可以省略不写,mas_equalTo包含equalTo
            make.left.mas_equalTo(self.view).offset(20);
            make.right.mas_equalTo(self.view).offset(-20);
            make.bottom.mas_equalTo(self.view).offset(-20);
            make.height.mas_equalTo(100);
            
            //1.2 相对于父控件可以省略不写
            make.left.offset(20);
            make.right.offset(-20);
            make.bottom.offset(-20);
            make.height.mas_equalTo(100);
            
            //1.3 距离相等可以并列写
            make.left.offset(20);
            make.right.bottom.offset(-20);
            make.height.mas_equalTo(100);
            
            //1.3 距离相等可以并列写
            make.left.offset(20);
            make.right.bottom.offset(-20);
            make.height.mas_equalTo(100);
        }];
    

    MASConstraintMaker定义的其他属性可以查看MasonrySDK(反正也是开源的)

    • 更新约束并且添加动画
    [mview mas_updateConstraints:^(MASConstraintMaker *make) {
            make.height.mas_equalTo(200);
        }];
        
        [UIView animateWithDuration:1.0 animations:^{
            [self.view layoutIfNeeded];
        }];
    

    6.UITableView

    • cell中的contentView作用是更容易做侧滑删除,收藏。
    • cell真实的frame
      cell:
    - (void)awakeFromNib {
        [super awakeFromNib];
        //cell在xib本身定义宽度 
        //NSLog(@"布局cell.width:%f-contentView.width%f",self.frame.size.width,self.contentView.frame.size.width);
    }
    //父控件尺寸确定好才会调用
    -(void)layoutSubviews
    {
        //tableview的宽度
        //NSLog(@"布局cell.width:%f-contentView.width%f",self.frame.size.width,self.contentView.frame.size.width);
    }
    

    vc:

    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    //开始是cell在xib中定义的宽度,滑动到第二次加载该view的时候才是tableview的宽度
        ZSTableViewCell * cell=[tableView dequeueReusableCellWithIdentifier:@"cell"];
        NSLog(@"代理方法cell.width:%f-contentView.width%f",cell.frame.size.width,cell.contentView.frame.size.width);
        return cell;
    }
    

    所以在cell的layoutSubviews方法中才能拿到实际的frame

    • 静态Cell
      a.创建storyborad,拖一个uitableviewcontroller到sb中。
      b.改变该uitableview类型为static cells,并指定uitableviewcontroller标识。
      c.创建控制器和该uitableviewcontroller关联。
      d.代码跳转
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"sb名称" bundle:nil];
        StaticCellTableViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"tvc标识"];
        [self presentViewController:vc animated:YES completion:nil];
    
    • 调用顺序
      tableview第一次创建出来:
    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        NSLog(@"heightForRowAtIndexPath");
        return 50;
    }
    
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        NSLog(@"cellForRowAtIndexPath");
        ZSTableViewCell * cell=[tableView dequeueReusableCellWithIdentifier:@"cell"];
        cell.name=@"";
        return cell;
    }
    
    - (void)awakeFromNib {
        [super awakeFromNib];
        NSLog(@"awakeFromNib");
    }
    
    -(void)layoutSubviews
    {
        NSLog(@"layoutSubviews");
    }
    -(void)setName:(NSString *)name
    {
        NSLog(@"setName");
        _name=name;
    }
    

    tableview:heightForRowAtIndexPath(可见范围内的)->
    tableview:cellForRowAtIndexPath->
    cell:awakeFromNib->
    tableview:setData->
    cell:layoutSubviews

    cellForRowAtIndexPath优先于awakeFromNib,是因为[tableView dequeueReusableCellWithIdentifier:@"cell"]的方法内部让cell初始化;
    setData方法优先于layoutSubviews,是因为在每个cellForRowAtIndexPath方法执行完毕才添加该cell到tableview中;
    cell:awakeFromNib只会在第一次创建时候调用,原因是tableview复用机制。

    所以在layoutSubviews使用模型不会有问题,也能解释为什么layoutSubviews中才能获取真正cell的frame。
    • 不定行高的cell的警告可以通过修改约束优先级擦除。
    • tableview局部刷新的前提是要保证数组数据长度不变,除非使用
    self.tableview insertSections:<#(nonnull NSIndexSet *)#> withRowAnimation:<#(UITableViewRowAnimation)#>
    
    self.tableview deleteSections:<#(nonnull NSIndexSet *)#> withRowAnimation:<#(UITableViewRowAnimation)#>
    
    
    • cell侧滑按钮设置
      a.只实现单一按钮功能,比如删除
    //实现这两个代理
    -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
    {
        NSLog(@"删除改行");
    }
    
    -(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return @"删除";
    }
    

    b.实现侧滑多按钮功能

    -(NSArray<UITableViewRowAction*>*)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewRowAction * row1=[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"编辑" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
            NSLog(@"编辑");
        }];
        
        UITableViewRowAction * row2=[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
            NSLog(@"删除");
        }];
        
        row2.backgroundColor=[UIColor blueColor];
        return @[row1,row2];
    }
    
    • 多cell选中功能
    //1.设置属性
    self.tableView.allowsMultipleSelectionDuringEditing=YES;
    //2.进入tableview编辑模式
     [self.tableView setEditing:YES animated:YES];
    //3.获得选中cell的indexPath
    NSArray<NSIndexPath*> * selectedRows=self.tableView.indexPathsForSelectedRows;
    //注意点:
    //批量删除注意点,删除数组中的模型,而不是直接删除对应index,因为删除一个index的元素时,整体数组index会改变
    
    • 分割线通栏
    cell.layoutMargins=UIEdgeInsetsZero;//iOS(8.0)
    
    • 解决xib初始化控件尺寸的拉伸问题
    - (void)awakeFromNib {
        [super awakeFromNib];
        self.autoresizingMask=UIViewAutoresizingNone;
    }
    
    • 解决UITableView刷新跳动问题
    if (@available(iOS 11.0, *)) {
            UITableView.appearance.estimatedRowHeight = 0;
            UITableView.appearance.estimatedSectionFooterHeight = 0;
            UITableView.appearance.estimatedSectionHeaderHeight = 0;
        }
    

    7.使用技巧

    a.StackView很好用,但是只能是IOS9.0以后。
    b.比例控件
    xib中控件可以通过向父控件拖拽equal width或者height,然后调节比率完成按照比例实现控件宽高。也可以向自己拖拽aspect ratio属性,控制控件自己的宽高比。
    c.居中偏差
    控件先horizontally or verticality in container,然后对约束Edit,调整constant的值,让控件按居中位置偏移。
    d.实现多个View平分的效果,可以使用辅助View,设置各个View间距为0,然后隐藏掉辅助控件。
    e.A B 垂直或者水平中心对齐,可以拖拽B到A身上,也可以多选A,B选择horizontal/vertical centers。

    五、CALayer

    1.CATransform3D是layer比UIView拓展的属性,支持3D形变。

    2.position和anchorPoint

    • 概念:
      position->用来设置CALayer在父层中的位置
      anchorPoint->决定CALayer身上哪个点会在position所指的位置,默认(0.5,0.5)范围0-1

    • 修改anchorPoint的值,position不改变。
      比如:在控制器View上添加一个View,frame是(100,100,100,100)
      View的中心点center=layer.position是(150,150),锚点是(0.5,0.5)
      如果修改锚点值为(0,0),position(150,150)-(当前View左上角),frame变成(150,150,100,100)
      修改anchorPoint为(0,0)->position不变,(150,150)点固定,如果想要保证position所指的位置在修改后的锚点在左上角(0,0),那么自然UIView要向右下方向移动。
      如果修改锚点值为(1,1),position(150,150)-(当前View右下角),frame变成(50,50,100,100)

    • 作用:
      使用旋转动画的话,锚点是旋转点中心点位置,默认是中心旋转,如果设置为(0,0),以左上角为中心点旋转。

    3.隐式动画

    每一个UIView都关联一个CALayer,默认是RootLayer。
    所有非RootLayer,手动创建的CALayer,都有隐式动画。

    4.核心动画CAAnimation

    CABasicAnimation

        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
        animation.delegate=self;
        //动画选项的设定
        animation.duration = 2.5; // 持续时间
        animation.repeatCount = 1; // 重复次数
        // 起始帧和终止帧的设定
        animation.fromValue = [NSValue valueWithCGPoint:self.phoneBtn.layer.position]; // 起始帧
        animation.toValue = [NSValue valueWithCGPoint:CGPointMake(320, 480)]; // 终止帧
        //动画结束停在终止帧位置
        animation.removedOnCompletion = NO;
        animation.fillMode=kCAFillModeForwards;
        // 添加动画
        [self.phoneBtn.layer addAnimation:animation forKey:@"move-layer"];
    

    CAKeyframeAnimation

        CAKeyframeAnimation * key=[CAKeyframeAnimation animation];
        UIBezierPath * path=[UIBezierPath bezierPath];
        [path moveToPoint:CGPointMake(0, 0)];
        [path addLineToPoint:CGPointMake(1, 1)];
        key.path=path.CGPath;
        key.rotationMode=@"autoReverse";
        [self.phoneBtn.layer addAnimation:key forKey:@"move-layer"];
    

    CATransition
    页面翻页各种效果

    UIView动画和CA核心动画区别
    • UIView动画是对该UIView的属性进行改变的延时效果
    常用属性比如改变frame,transform,alpha。
    

    改变属性的相互响应:

    1.当一个view的frame被更改时
    a.当更改size时,它的bounds的width和height会被更改为与frame的size一致,但是bounds的origin不会被更改。view的center,layer的position可能会被更改。
    b.当更改origin时,对bounds属性无影响。view的center,layer的position可能会被更改。
    
    2.当一个view的bounds被更改时
    a.当更改size时,frame的width和size会改为同bounds的size一致,frame的origin有可能更改(取决于layer的anchorPoint)。view的center,layer的position可能会被更改不会更改。
    b.当更改origin时,frame无影响,view的center,layer的position不会更改。
    
    3.当view的center更改时
    frame的origin会更改,layer的position会更改。
    
    4.当一个view的transform被更改了,即不为CGAffineTransformIdentity。
    frame属性可能会更改,view的bounds,center不会变,layer的position不会变。这个很重要,这样保持了在transform后,view的frame虽然改变了,但是内部参考系是不变的,可以继续进行其他变换,只要不更改frame或center或layer的position。
    

    CA核心动画对该UIView的属性不改变(比如一个位移动画让UIView改变位置只是看起来改变了,其实位置还在初始点位置,点击原始位置才会有响应,点击看到UIView的终止帧位置没响应,是一种动画假象)

    • UIView是直接作用在该UIView属性上的,CA核心动画作用在CALayer上
    • 一般有交互事件的UIView,尤其是位移改变还做交互的UIView不做CA核心动画,单纯的帧动画或者转场效果可以做CA核心动画。

    UIView物理动画

    [UIViewanimateWithDuration:1.0delay:2.0usingSpringWithDamping:0.5initialSpringVelocity:0.1options:UIViewAnimationOptionTransitionFlipFromTopanimations:^{
    CGRectviewFrame =_view3.frame;
    viewFrame.origin.x+=transweight;
    _view3.frame=viewFrame;
    }completion:nil];
    

    六、UIImageView

    1.显示部分图片(截取图片指定区域显示到当前UIImageView上)

    //截取图片上半部分填充到testImg中
    self.testImg.layer.contentsRect=CGRectMake(0, 0, 1, 0.5);
    

    2.最近项目中有关于自定义相机以及对拍完照片裁剪的一些问题,总结出来和大家分享一下。

    http://www.cocoachina.com/ios/20150605/12021.html

    3.UIImageView的contentMode

    typedef NS_ENUM(NSInteger, UIViewContentMode) {
    //如果包含Scale,按照ImageView尺寸进行填充
        UIViewContentModeScaleToFill, //完全按照ImageView尺寸填充(不会超出ImageView尺寸)
        UIViewContentModeScaleAspectFit, //按照原始图像宽高比在ImageView尺寸内填充(不会超 出ImageView尺寸)
        UIViewContentModeScaleAspectFill, //按照原始图像宽高比填充,使得宽度或者长度等于 ImageView尺寸的宽度或者长度(可能超出ImageView尺寸)
    //如果不包含Scale,按照图像原始比例进行填充,结合clipsToBounds属性,保证不超出UIImageView尺寸
        UIViewContentModeRedraw,              
        UIViewContentModeCenter,            
        UIViewContentModeTop,
        UIViewContentModeBottom,
        UIViewContentModeLeft,
        UIViewContentModeRight,
        UIViewContentModeTopLeft,
        UIViewContentModeTopRight,
        UIViewContentModeBottomLeft,
        UIViewContentModeBottomRight,
    };
    

    七、UICollectionView

    1.使用注意

    UICollectionView初始化必须指定该UICollectionView的布局样式Layout。
    Layout可以控制该UICollectionView显示样式。

    UICollectionViewFlowLayout * layout=[[UICollectionViewFlowLayout alloc]init];
        /*
          中间间隔
          如果UICollectionViewScrollDirectionVertical:
          定义最小间隔的原因是因为CollectionView横向布局放不下会自动换行,所以此时间隔就不是定义的间隔了
        */
        layout.minimumInteritemSpacing=1;
        /*
          行间距
          如果UICollectionViewScrollDirectionHorizontal:
          定义最小行间距的原因是因为CollectionView纵向布局放不下会自动换行,所以此时间隔就不是定义的间隔了
        */
        layout.minimumLineSpacing=1;
        //itemSize
        layout.itemSize=CGSizeMake(100, 100);
        /*
         滑动方向UICollectionViewScrollDirectionVertical
         0246
         1357
         滑动方向UICollectionViewScrollDirectionHorizontal
         01
         23
         45
         67
         */
        layout.scrollDirection=UICollectionViewScrollDirectionHorizontal;
        UICollectionView * collectionView=[[UICollectionView alloc]initWithFrame:CGRectMake(0, 100, 300, 300) collectionViewLayout:layout];
        [collectionView registerNib:[UINib nibWithNibName:@"TestCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"testCollectionViewCell"];
        collectionView.delegate=self;
        collectionView.dataSource=self;
        [self.view addSubview:collectionView];
    

    结论:间距和itemSize设置要合理才不会让布局错乱;Bannel和引导页都可以使用横向滑动的CollectionView做。

    相关文章

      网友评论

          本文标题:UIView的深入理解

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