iOS tips 6

2016-01-01 | 阅读

AutoLayout相关函数

  • -(void)sizeToFit : 该方法自动调用 sizeThatFits方法,不应该被重写,可手动调用.
  • -(CGSize)sizeThatFits:(CGSize)size : 传入的参数是当前的Size,返回一个适配后合适的Size.

sizeToFit可以被手动直接调用 ,sizeToFitsizeThatFits方法都没有递归,对subviews也不负责,只负责自己.

  • -(void)layoutSubviews : 进行重新布局,调用先于drawRect. 默认是不做任何事,需要子类重写.
  • -(void)layoutIfNeeded : 对该View判断是否需要重新布局,会遍历子View的链.如果需要,立即调用layoutSubviews来进行布局.
  • -(void)setNeedsLayout : 设置一个需要重新布局的标记,然后在下一次的runloop 中执行.

layoutSubviews会在以下情况被调用:

  1. 在使用initWithFrame: 进行初始化时(实际上直接使用init就是在调用initWithFrame: CGRectZero) rect的值不为CGRectZero时,会调用layoutSubviews . 需要注意,在iOS7版本以及iOS7之前的版本上,不会去区分这个CGRectZero,默认是调用layoutSubviews.
  2. addSubview会触发layoutSubviews
  3. 设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
  4. 滚动一个UIScrollView会触发layoutSubviews
  5. 旋转Screen会触发父UIView上的layoutSubviews事件
  6. 改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件,这里是在类的内部调整子视图的位置,即由该组件自己改变自己的subview的位置时,会触发,但是如果是外部来修改subviews的位置,就不会调用.

触发的时候,是调用 setNeedsLayout 来设置标签.

  • -(void)setNeedsDisplay : 设置一个需要重新绘图的标签,下个draw周期重绘. iphone device刷新频率为60hz,也就是大约1/60秒后进行重绘.
  • -(void)drawRect : 重绘组件

基于约束的AutoLayer的方法:

  • setNeedsUpdateConstraints : 当一个自定义view的某个属性发生改变,并且可能影响到constraint时,需要调用此方法去标记constraints需要在未来的某个点更新,系统然后调用updateConstraints.
  • (BOOL)needsUpdateConstraints : constraint-based layout system使用此返回值去决定是否需要调用updateConstraints作为正常布局过程的一部分。
  • updateConstraintsIfNeeded : 立即触发约束更新,自动更新布局。
  • updateConstraints : 自定义view应该重写此方法在其中建立constraints. 注意:要在实现最后调用[super updateConstraints]

自动布局的过程: updating constraints->layout->display.先检测constraints,来判断是否有约束改变,这个过程一般是从下向上的,subview约束发送变化,向上传递给superView来进行检测.全部检测完成后,在进行layout.在进行layout,该过程是从上到下的,此步用上一步的信息去设置view的center和bounds.最后是display,来进行view的绘制渲染.

即,如果使用自动布局,就将布局操作放在updateConstraints中,如果不用自动布局,使用frame来设置布局位置,就将这样的手动固定布局放在layoutSubviews中.

iOS二维码扫描

系统的AVFoundation中提供了二维码扫描的功能

 //获取摄像设备
AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
//创建输入流
AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
//创建输出流
AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];
//设置代理 在主线程里刷新
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
//初始化链接对象
_avsession = [[AVCaptureSession alloc]init];
[_avsession addInput:input];
[_avsession addOutput:output];
//设置扫码支持的编码格式,二维码
output.metadataObjectTypes=@[AVMetadataObjectTypeQRCode];
_metadataOutput = output;
// 预览图层
_scannerLayer = [AVCaptureVideoPreviewLayer layerWithSession:_avsession];
_scannerLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;
_scannerLayer.frame=self.view.layer.bounds;
[self.view.layer insertSublayer:_scannerLayer atIndex:0];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(changeOutputRect)
                                             name:AVCaptureInputPortFormatDescriptionDidChangeNotification
                                           object:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self changeOutputRect];
});
[_avsession startRunning];

UIButton中的EdgeInsets

UIButton中默认同时存在图片和文字, 即一个titleLabel 和一个 imageView,默认为图片在左文字在右,可以简单的通过contentHorizontalAlignmentUIControlContentVerticalAlignment来控制两者整体的布局.

要想改变两个控件的显示位置,通过setTitleEdgeInsetssetImageEdgeInsets来实现.

[btn setTitleEdgeInsets:UIEdgeInsetsMake(10,20, 0, 0)];

第一个是top,第二个是left,也就是说,向下移动10个单位,再向右移动10个单位.

objc_msgSend too many arguments to function call

解决方法 Enable strict checking of objc_msgSend calls 选择 NO.