前言
在开发中我们大多都会使用Masonry来做约束,因为这个的确方便。但是呢最近在做一个自己的项目的时候偶然发现了一个问题。
问题
这个问题很简单,就是我在适配上出现了问题,以下是正常效果和问题效果图对比:
那么要说到出现这个问题的原因是,首先就得说一下我做屏幕适配的做法。我的做法是我以iPhone6/iPhone6s为基本的模板来做,比如说在iPhone6/iPhone6s上是多少的点,那么最后都会乘以一个屏幕因子:
#define kDeviceFactor ([UIScreen mainScreen].bounds.size.width / 375.0)
基本的做法:
1>左边的categoryTableView分类的UITableView在iPhone6/iPhone6s上90个点,然后后面的categoryCollectionView是以左边的categoryTableView来做约束的,然后两个视图中间是没有间隔的,只不过因为我要做阴影效果,所以section的左右都内缩了10,然后中间的minimumLineSpacing和minimumInteritemSpacing都给的7,所以根据以下的这些算出了每一个item的itemSize,按道理是不会出现图上的这种情况的。
//这个是两个视图中间的间隔
CGFloat collectionView2TableViewMargin = 0;
//sectionInset设置
CGFloat collectionViewSectionInsetLeft = 10;
CGFloat collectionViewSectionInsetRight = 10;
CGFloat collectionViewSectionInsetTop = 10;
CGFloat collectionViewSectionInsetBottom = 0;
flowLayout.sectionInset = UIEdgeInsetsMake(collectionViewSectionInsetTop, collectionViewSectionInsetLeft, collectionViewSectionInsetBottom, collectionViewSectionInsetRight);
//这个是minimumLineSpacing和minimumInteritemSpacing的值
CGFloat itemNums = 3;
CGFloat minimumLineAndInteritemSpacing = 7;
//这个是左边的categoryTableView适应各种不同屏幕的宽度
CGFloat categoryTableViewWidth = kCategoryTableViewWidth * kDeviceFactor;
//算出的itemSize
CGFloat itemSizeWidth = (kScreenWidth - categoryTableViewWidth - collectionViewSectionInsetLeft - collectionViewSectionInsetRight - collectionView2TableViewMargin - minimumLineAndInteritemSpacing * (itemNums - 1))/ itemNums;
看了一下完全没有问题,但是呢就是会出现以上的效果,这就很头疼了。那么唯一的解决思路是看下每一个视图的参数是不是和算出来的一致,经过查看视图结果发现了一个问题,就是categoryTableView的宽度是不同的,在iPhone5上打断点算出的categoryTableViewWidth为76.8多,请看大屏幕:
但是呢打开视图结构发现:
发现这个是77,那这个就有问题了,后面经过诸多尝试发现这个问题出在:
这里的kCategoryTableViewWidth * kDeviceFactor算出来的正是categoryTableViewWidth,但是经过这个之后categoryTableView的实际约束后的宽度就变成了77了,经过尝试发现:
- [76.0,76.25) 对应76.0
- [76.25,76.75) 对应76.5
- [76.75,77] 对应77
这是经过mas_equalTo装箱后得到的处理,所以经过这里我们找到了罪魁祸首了,那怎么处理呢?
处理
两种方式:
第一种:
我们可以在mas_equalTo装箱之前经过以上Masonry想似的处理然后我们在后面用的时候也是经过处理后的数
第二种:
我们可以在layoutSubViews方法内部再去算,因为这个时候真正的frame已经出来了,我们可以根据这个再去算一遍,那就可以避免相应的问题了。
我的方式是一种,我自己经过了处理,大家只要把工程中ViewController.m文件中的两处注释打开就可以看到效果了:
#pragma mark - private methods
- (CGFloat)convertTheFloatNum:(CGFloat)number{
if (number - (int)number >= 0.75) {
number = (int)number + 1.0;
}else if(number - (int)number >= 0.25 ) {
number = (int)number + 0.5;
}else{
number = (int)number + 0.0;
}
return number;
}
PS: 但是其实说到这里我还是觉得不用Masonry约束的好,或者说可以部分利用Masonry。
- 像整体部分的构件还是用直接写死frame为好,然后再根据屏幕因子做适配
- 像大的控件内部的部件就可以用Masnory来做约束,这样既能提高效率也能避免出现太多约束的问题,因为约束一旦出现问题很难找...
Demo在此
希望能给大家带来帮助,以上!!!