立即获取UIButton子视图的准确宽高

概述

  1. UIButton默认的布局是imageView在左, titleLabel在右, 需求正好相反, 并且, imageViewtitleLabel之间需要一定的间距.
  2. 新建UIButton之后, 立即为其指定了需要显示的文案和图片, 这时, 需要立即获取imageViewtitleLabel的尺寸以调整偏移量, 达到需求的目的.
    在这里插入图片描述

遇到的问题

	NSString *selectedCityNameString = @"上海";
	// 指定字体, 颜色, 和图片
    UIButton *citySelectedBtn = [UIButton sqi_buttonForNormalStateWithFont:PFSCS(12) titleColor:COLOR_BLACK title:selectedCityNameString];
    [citySelectedBtn setImage:IMG(@"tk_icon_triangle_down_black") forState:UIControlStateNormal];
    // 此时立即获取子视图的宽高, 发现是错误的
    NSLog(@"图片的宽度 -> %lf", citySelectedBtn.imageView.bounds.size.width);
    NSLog(@"Label的宽度 -> %lf", citySelectedBtn.titleLabel.bounds.size.width);

解决办法

  1. 正确: 在获取子视图之前调用sizeToFit;
  2. 错误方法: 在获取子视图之前调用layoutIfNeeded;
  3. 错误方法: 在获取子视图之前调用setNeedsLayout;
  4. 推测正确的方法: dispatch_after方法中获取宽高;
	NSString *selectedCityNameString = @"上海";
	// 指定字体, 颜色, 和图片
    UIButton *citySelectedBtn = [UIButton sqi_buttonForNormalStateWithFont:PFSCS(12) titleColor:COLOR_BLACK title:selectedCityNameString];
    [citySelectedBtn setImage:IMG(@"tk_icon_triangle_down_black") forState:UIControlStateNormal];
    // 正确
    // [citySelectedBtn sizeToFit];
    // 错误
    //  [citySelectedBtn setNeedsLayout];
    // 错误
    // [citySelectedBtn layoutIfNeeded];
    NSLog(@"图片的宽度 -> %lf", citySelectedBtn.imageView.bounds.size.width);
    NSLog(@"Label的宽度 -> %lf", citySelectedBtn.titleLabel.bounds.size.width);

本质原因分析

  1. 在按钮被添加到父视图之前, 按钮本身并不知道应该怎样布局, 所以你发送setNeedsLayout 或者 layoutIfNeeded 消息的时候, 按钮还是不知道该怎么布局(并没有像sizeToFit一样为按钮指定布局规则), 所以此时获取按钮宽高, 必定还是错误的. 而调用sizeToFit方法后, 按钮知道了该怎么布局子控件和怎样调整本身宽高来 siseToFit 子控件, 所以, 此时获取宽高, 必定是正确和准确无误的. 而dispatch_after方法内部的代码库是在下一个runloop执行的, 在那个时候, 按钮已经被添加到父视图上了, 按钮本身当然已经知道该怎样布局自身, 所以获取的宽高应该是准确的.
  2. 推测UIButton的内部实现, 在被添加到父视图之上的时候, 才会为其制定布局(Frame)和约束, 所以未添加到父视图的时候, 调用setNeedsLayoutsetNeedsLayout是不会促使它更新自己的布局(或者Frame, 宽高).

由于时间仓促, 博主水平有限, 错误与疏漏之处敬请读者批评指正.

你可能感兴趣的:(iOS开发)