点步

导航

layoutsubviews

layoutSubviews在以下情况下会被调用: 

1、init初始化不会触发layoutSubviews 
2、addSubview会触发layoutSubviews 
3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化 
4、滚动一个UIScrollView会触发layoutSubviews 
5、旋转Screen会触发父UIView上的layoutSubviews事件 
6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件

layoutSubviews 当需要重新布局视图元素时候会用到这个方法;

 

在iOS5.1或之前的版本中,这个方法什么也没干.这个方法的默认实现是 用参数来设定subviews的尺寸和位置的 .

 

如果你需要更加精确的布局,可以在子类里面重写这个方法.仅仅在以下情况下:自动布局达不到你想要效果时你才有必要重写这个方法.你可以直接设置subviews的尺寸.

 

你不能直接调用这个方法.如果你需要强制layout刷新,调用setNeedsLayout来代替.如果你想要立即刷新你的view,调用layoutIfNeeded

 

大概总结以下就是:

你不要直接调用方法layoutSubviews,如果想要刷新,请调用 setNeedsLayout 或者 layoutIfNeeded

好了,开始验证:)

现在提供继承至UIView的类如下:

//
//  TestView.h
//  LayoutSubviews
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface TestView : UIView

@end
//
//  TestView.m
//  LayoutSubviews
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "TestView.h"

@implementation TestView

- (id)initWithFrame:(CGRect)frame
{
  self = [super initWithFrame:frame];
  if (self)
  {
    NSLog(@"initWithFrame:%@" ,NSStringFromCGRect(frame));
  }
  return self;
}

- (void)layoutSubviews
{
  NSLog(@"layoutSubviews %@", self);
  [super layoutSubviews];
}

@end

测试代码:

//
//  RootViewController.m
//  LayoutSubviews
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "RootViewController.h"
#import "TestView.h"

@interface RootViewController ()

@property (nonatomic, strong) NSTimer   *timer;
@property (nonatomic, strong) TestView  *largeView;
@property (nonatomic, strong) TestView  *smallView;

@end

@implementation RootViewController


- (void)viewDidLoad
{
  [super viewDidLoad];

  // 1、init初始化不会触发layoutSubviews [正确的]
  // 2、addSubview会触发layoutSubviews [不完全正确,当frame为0时是不会触发的]
  // 3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化 [正确]
  
//	[self test_1];
//	[self test_2];
//	[self test_3];
  
  // 4、滚动一个UIScrollView会触发layoutSubviews[错误,不用滚动就会触发]
//	[self test_4];
  
  // 5、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件
  [self test_5];
}


- (void)test_1
{
  /* 
   解释:
   
   走了initWithFrame:方法,但是又有frame值为{{0, 0}, {0, 0}},并不需要绘制任何的东西,
   所以即使添加了test,也没必要绘制它,同时也验证了addSubview会触发layoutSubviews是错
   误的,只有当被添加的view有着尺寸的时候才会触发layoutSubviews
   */
  
  TestView *test = [TestView new];
  [self.view addSubview:test];
}

- (void)test_2
{
  TestView *test = [TestView new];
  test.frame = CGRectMake(0, 0, 100, 100);
  [self.view addSubview:test];
}

- (void)test_3
{
  /*
   解释:
   
   layoutSubviews这个方法自身无法调用,是被父类添加的时候才执行的方法
   */
  
  TestView *test = [TestView new];
  test.frame = CGRectMake(0, 0, 50, 50);
  UIView *showView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
  [test addSubview:showView];
}

- (void)test_4
{
  CGRect rect	= self.view.bounds;
  CGFloat height = rect.size.height;
  CGFloat width  = rect.size.width;
  
  UIScrollView *rootScroll = [[UIScrollView alloc] initWithFrame:self.view.bounds];
  NSArray *data			= @[@"", @"", @"", @""];
  [data enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    TestView *tmp		= [[TestView alloc] initWithFrame:CGRectMake(width*idx, 0,
                                      width, height)];
    [rootScroll addSubview:tmp];
  }];
  rootScroll.contentSize   = CGSizeMake(width * data.count, height);
  [self.view addSubview:rootScroll];
}

- (void)test_5
{
  _timer = [NSTimer scheduledTimerWithTimeInterval:1.f
                        target:self
                      selector:@selector(timerEvent:)
                      userInfo:nil
                       repeats:YES];
  _largeView = [[TestView alloc] initWithFrame:self.view.bounds];
  [self.view addSubview:_largeView];
  
  _smallView = [[TestView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
  [_largeView addSubview:_smallView];
}

- (void)timerEvent:(id)sender
{
  _smallView.frame = CGRectMake(arc4random()%100 + 20,
                  arc4random()%100 + 20,
                  arc4random()%100 + 20,
                  arc4random()%100 + 20);
  NSLog(@"_smallView %@", _smallView);
  NSLog(@"_smallView %@", _largeView);
}

@end

测试后的结论是这样子的:

1. 一个view是不能够自己调用layoutSubviews,如果要调用,需要调用 setNeedsLayout或者 layoutIfNeeded

2. 如果view的frame值为0,即使被添加了耶不会调用layoutSubviews

3. 如果一个view的frame值改变了,那么它的父类的layoutSubviews也会被执行

posted on 2015-11-06 21:26  点步  阅读(398)  评论(0编辑  收藏  举报