解析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到底是啥来着:)

Lays out subviews.
The default implementation of this method does nothing on iOS 5.1 and earlier. Otherwise, the default implementation uses any constraints you have set to determine the size and position of any subviews.

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

Subclasses can override this method as needed to perform more precise layout of their subviews. You should override this method only if the autoresizing and constraint-based behaviors of the subviews do not offer the behavior you want. You can use your implementation to set the frame rectangles of your subviews directly.

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

You should not call this method directly. If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded method.

你不能直接调用这个方法.如果你需要强制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也会被执行

解析LayoutSubviews

时间: 2024-10-03 21:54:19

解析LayoutSubviews的相关文章

[转] 解析LayoutSubviews

转自: http://www.cnblogs.com/YouXianMing/p/3897543.html 从百度上搜索了一下layoutSubviews的用处,以下是搜索的结果,当然,笔者是会一一验证的. 1.init初始化不会触发layoutSubviews 2.addSubview会触发layoutSubviews 3.设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化 4.滚动一个UIScrollView会触发layoutSubview

iOS中中UIView头文件详细解析

@interface UIView : UIResponder<NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem> /** *  通过一个frame来初始化一个UI控件 */ - (id)initWithFrame:(CGRect)frame; // YES:能够跟用户进行交互 @property(nonatomic,getter=isUserInteractionEnabled) BOOL userInteraction

用json方法解析本地数据,并显示在tableView上面

效果图  图片是三张星星图片,1是全星,2是半星,3是空星 类的文件 AppDelegate.m #import "AppDelegate.h" #import "MainViewController.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOp

iOS对UIViewController生命周期和属性方法的解析

目录[-] iOS对UIViewController生命周期和属性方法的解析 一.引言 二.UIViewController的生命周期 三.从storyBoard加载UIViewController实例的传值陷阱 四.UIViewController与StroyBoard的相关相互方法 1.ViewController直接在StoryBoard中进行跳转的传值 2.使用代码跳转Storyboard中的controller 五.UIViewController之间的一些从属关系 1.parentV

【iOS开发】iOS对UIViewController生命周期和属性方法的解析

iOS对UIViewController生命周期和属性方法的解析 一.引言 作为MVC设计模式中的C,Controller一直扮演着项目开发中最重要的角色,它是视图和数据的桥梁,通过它的管理,将数据有条有理的展示在我们的View层上.iOS中的UIViewController是UIKit框架中最基本的一个类.从第一个UI视图到复杂完整项目,都离不开UIViewController作为基础.基于UIViewController的封装和扩展,也能够出色的完成各种复杂界面逻辑.这篇博客,旨在讨论UIV

C++工程编译之“error LNK2001: 无法解析的外部符号”

今天一整天都在折腾“error LNK2001: 无法解析的外部符号”,就在头疼不已的时候,总算是找到问题原因了:各个动态链接库的编译方式必须统一才行,要不然很容易对库函数的引用产生冲突.简单来说就是,如果使用的第三方函数库编译方式采用/MD,那么主工程也应该使用/MD.我使用了libevent,而主工程默认采用/MT,所以需要忽略一大堆的函数库,我还纳闷呢,怎么会这么奇怪!!今天总算是解决了长久以来的困惑了. 下面引用一篇文章的描述:[Z]VC运行库版本不同导致链接.LIB静态库时发生重复定义

防止恶意解析——禁止通过IP直接访问网站

一.什么是恶意解析 一般情况下,要使域名能访问到网站需要两步,第一步,将域名解析到网站所在的主机,第二步,在web服务器中将域名与相应的网站绑定.但是,如果通过主机IP能直接访问某网站,那么把域名解析到这个IP也将能访问到该网站,而无需在主机上绑定,也就是说任何人将任何域名解析到这个IP就能访问到这个网站.可能您并不介意通过别人的域名访问到您的网站,但是如果这个域名是未备案域名呢?一旦被查出,封IP.拔线甚至罚款的后果都是需要您来承担的.某些别有用心的人,通过将未备案域名解析到别人的主机上,使其

.NET深入解析LINQ框架(五:IQueryable、IQueryProvider接口详解)

阅读目录: 1.环路执行对象模型.碎片化执行模型(假递归式调用) 2.N层对象执行模型(纵横向对比链式扩展方法) 3.LINQ查询表达式和链式查询方法其实都是空壳子 4.详细的对象结构图(对象的执行原理) 5.IQueryable<T>与IQueryProvider一对一的关系能否改成一对多的关系 6.完整的自定义查询 1]. 环路执行对象模型.碎片化执行模型(假递归式调用) 这个主题扯的可能有点远,但是它关系着整个LINQ框架的设计结构,至少在我还没有搞懂LINQ的本意之前,在我脑海里一直频

.NET深入解析LINQ框架(一:LINQ优雅的前奏)

阅读目录: 1.LINQ简述 2.LINQ优雅前奏的音符 2.1.隐式类型 (由编辑器自动根据表达式推断出对象的最终类型) 2.2.对象初始化器 (简化了对象的创建及初始化的过程) 2.3.Lambda表达式 (对匿名方法的改进,加入了委托签名的类型推断并很好的与表达式树的结合) 2.4.扩展方法 (允许在不修改类型的内部代码的情况下为类型添加独立的行为) 2.5.匿名类型 (由对象初始化器推断得出的类型,该类型在编译后自动创建) 2.6.表达式目录树(用数据结构表示程序逻辑代码) 3.LINQ