说到iOS自动布局,有很多的解决办法。有的人使用xib/storyboard自动布局,也有人使用frame来适配。对于前者,笔者并不喜欢,也不支持。对于后者,更是麻烦,到处计算高度、宽度等,千万大量代码的冗余,对维护和开发的效率都很低。
笔者在这里介绍纯代码自动布局的第三方库:Masonry。这个库使用率相当高,在全世界都有大量的开发者在使用,其star
数量也是相当高的。
效果图
本节详解Masonry
的循环创建视图,并且可以展开与收缩的用法,先看看效果图:
当我们点击某一行时,可以展开:
核心代码
@interfaceScrollViewComplexController() @property(nonatomic,strong)UIScrollView*scrollView; @property(nonatomic,strong)NSMutableArray*expandStates; @end @implementationScrollViewComplexController -(void)viewDidLoad{ [superviewDidLoad]; self.scrollView=[[UIScrollViewalloc]init]; self.scrollView.pagingEnabled=NO; [self.viewaddSubview:self.scrollView]; self.scrollView.backgroundColor=[UIColorlightGrayColor]; CGFloatscreenWidth=[UIScreenmainScreen].bounds.size.width; UILabel*lastLabel=nil; for(NSUIntegeri=0;i<10;++i){ UILabel*label=[[UILabelalloc]init]; label.numberOfLines=0; label.layer.borderColor=[UIColorgreenColor].CGColor; label.layer.borderWidth=2.0; label.text=[selfrandomText]; label.userInteractionEnabled=YES; UITapGestureRecognizer*tap=[[UITapGestureRecognizeralloc]initWithTarget:selfaction:@selector(onTap:)]; [labeladdGestureRecognizer:tap]; //WemustpreferredMaxLayoutWidthpropertyforadaptingtoiOS6.0 label.preferredMaxLayoutWidth=screenWidth-30; label.textAlignment=NSTextAlignmentLeft; label.textColor=[selfrandomColor]; [self.scrollViewaddSubview:label]; [labelmas_makeConstraints:^(MASConstraintMaker*make){ make.left.mas_equalTo(15); make.right.mas_equalTo(self.view).offset(-15); if(lastLabel){ make.top.mas_equalTo(lastLabel.mas_bottom).offset(20); }else{ make.top.mas_equalTo(self.scrollView).offset(20); } make.height.mas_equalTo(40); }]; lastLabel=label; [self.expandStatesaddObject:[@[label,@(NO)]mutableCopy]]; } [self.scrollViewmas_makeConstraints:^(MASConstraintMaker*make){ make.edges.mas_equalTo(self.view); //让scrollview的contentSize随着内容的增多而变化 make.bottom.mas_equalTo(lastLabel.mas_bottom).offset(20); }]; } -(NSMutableArray*)expandStates{ if(_expandStates==nil){ _expandStates=[[NSMutableArrayalloc]init]; } return_expandStates; } -(UIColor*)randomColor{ CGFloathue=(arc4random()%256/256.0);//0.0to1.0 CGFloatsaturation=(arc4random()%128/256.0)+0.5;//0.5to1.0,awayfromwhite CGFloatbrightness=(arc4random()%128/256.0)+0.5;//0.5to1.0,awayfromblack return[UIColorcolorWithHue:huesaturation:saturationbrightness:brightnessalpha:1]; } -(NSString*)randomText{ CGFloatlength=arc4random()%150+5; NSMutableString*str=[[NSMutableStringalloc]init]; for(NSUIntegeri=0;i<length;++i){ [strappendString:@"测试数据很长,"]; } returnstr; } -(void)onTap:(UITapGestureRecognizer*)sender{ UIView*tapView=sender.view; NSUIntegerindex=0; for(NSMutableArray*arrayinself.expandStates){ UILabel*view=[arrayfirstObject]; if(view==tapView){ NSNumber*state=[arraylastObject]; if([stateboolValue]==YES){ [viewmas_updateConstraints:^(MASConstraintMaker*make){ make.height.mas_equalTo(40); }]; }else{ UIView*preView=nil; UIView*nextView=nil; if(index-1<self.expandStates.count&&index>=1){ preView=[[self.expandStatesobjectAtIndex:index-1]firstObject]; } if(index+1<self.expandStates.count){ nextView=[[self.expandStatesobjectAtIndex:index+1]firstObject]; } [viewmas_remakeConstraints:^(MASConstraintMaker*make){ if(preView){ make.top.mas_equalTo(preView.mas_bottom).offset(20); }else{ make.top.mas_equalTo(20); } make.left.mas_equalTo(15); make.right.mas_equalTo(self.view).offset(-15); }]; if(nextView){ [nextViewmas_updateConstraints:^(MASConstraintMaker*make){ make.top.mas_equalTo(view.mas_bottom).offset(20); }]; } } [arrayreplaceObjectAtIndex:1withObject:@(!state.boolValue)]; [self.viewsetNeedsUpdateConstraints]; [self.viewupdateConstraintsIfNeeded]; [UIViewanimateWithDuration:0.35animations:^{ [self.viewlayoutIfNeeded]; }completion:^(BOOLfinished){ }]; break; } index++; } } @end
讲解
当我们要收起的时候,只是简单地设置其高度的约束为40
,但是当我们要展开时,实现起来就相对麻烦了。因为我们需要重新添加约束,要重新给所点击的视图添加约束,就需要知道前一个依赖视图和后一个依赖视图的约束,以便将相关联的都更新约束。
当我们更新所点击的视图时,我们通过判断是否有前一个依赖视图来设置顶部约束:
if(preView){ make.top.mas_equalTo(preView.mas_bottom).offset(20); }else{ make.top.mas_equalTo(20); }
除了这个之外,我们也需要更新后一个视图的约束,因为我们对所点击的视图调用了mas_remakeConstraints
方法,就会移除其之前所添加的所有约束,所以我们必须重新将后者对当前点击的视图的依赖重新添加上去:
if(nextView){ [nextViewmas_updateConstraints:^(MASConstraintMaker*make){ make.top.mas_equalTo(view.mas_bottom).offset(20); }]; }
源代码
大家可以到笔者的github
下载源代码:MasonryDemo
温馨提示:本节所讲内容对应于ScrollViewComplexController
中的内容
推荐阅读
CocoaChina上有一篇文章讲得也不错,叫Masonry介绍与使用实践:快速上手Autolayout和IOS自适应前段库-Masonry的使用。
文章中所讲的内容属于很基础的内容,如果有任何疑问可以联系博主哦!