您好, , 海量一手媒体资源,专业、正规、高效,为企业提供一站式营销推广服务!
温馨提示
运营小帮手
一站式互联网营销服务平台
  全国免费咨询热线
0755-23071973
运营小帮手
软文发稿
PC端 选择媒体
更方便、更快捷!
查看媒体价格
软文发布、软文代写、百科制作、问答营销、微信营销、微信营销
查看媒体价格
当前位置: 运营小帮手首页 > 新闻中心 > 文章正文

iOS Masonry复杂ScrollView布局

说到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介绍与使用实践:快速上手AutolayoutIOS自适应前段库-Masonry的使用

文章中所讲的内容属于很基础的内容,如果有任何疑问可以联系博主哦!

关键词:

猜您可能需要的服务: