最近有在看一本关于auto layout的书,受益匪浅,然后突然想到我要解决的一个问题其实正好可以用到这个auto layout的技巧,现在进行一个讲解
我们之前看新闻、视频等的软件,常看到过这样的功能(如图蓝椭圆内)
我最早做这个功能的时候,是通过计算frame相应的值进行布局。其实这样很low,尤其如果button所对应的内容不一定时,计算就简直了,后来看了auto layout,觉得可以试一试使用它。
在这里主要涉及到俩个知识点,1.几何约束。2.内容约束
先晒代码,在做解释
#define buttonTag 1000
@interface ViewController ()
@property(nonatomic,strong)UIScrollView *scrollView;
@property(nonatomic,strong)NSArray *buttonContents;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.buttonContents = @[@"button1",@"longButton2",@"longlongButton3",@"btn",@"b",@"这是一个超长button",@"这个button更长更长更更长"];
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.scrollView];
UIButton *btn;
for (int i = 0; i < self.buttonContents.count; i++) {
btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.translatesAutoresizingMaskIntoConstraints = NO;
[btn setTitle:self.buttonContents[i] forState:UIControlStateNormal];
btn.tag = buttonTag+i;
[btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
[self.scrollView addSubview:btn];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:btn.intrinsicContentSize.width+10.0]];
if (i == 0) {
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.scrollView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.scrollView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:10]];
}else{
UIButton *preBtn = [self.scrollView viewWithTag:999+i];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:preBtn attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:btn attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:preBtn attribute:NSLayoutAttributeRight multiplier:1.0 constant:0]];
}
[btn layoutIfNeeded];
}
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:100]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:btn attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0]];
self.scrollView.contentSize = CGSizeMake(btn.frame.origin.x+btn.frame.size.width, btn.frame.size.height);
}
- (void)clickBtn:(id)sender{
UIButton *btn = (UIButton *)sender;
NSString *buttonContent = self.buttonContents[btn.tag - buttonTag];
NSLog(@"button title is %@",buttonContent);
}
最终结果如上图,图中区域可以左右滑动显示更多内容
flipBar只需要俩个控件,1.UIScrollView. 2.UIButton
如果有需要,你完全可以自定义一个UIButton。
1.首先需要初始化scrollView,注意不需要指定frame的具体值
2.其次涉及到translatesAutoresizingMaskIntoConstraints属性,它的默认值是YES.其中开发文档中是这样描述它
If this property’s value is YES, the system creates a set of constraints that duplicate the behavior specified by the view’s autoresizing mask. This also lets you modify the view’s size and location using the view’s frame, bounds, or center properties, allowing you to create a static, frame-based layout within Auto Layout.
Note that the autoresizing mask constraints fully specify the view’s size and position; therefore, you cannot add additional constraints to modify this size or position without introducing conflicts. If you want to use Auto Layout to dynamically calculate the size and position of your view, you must set this property to NO, and then provide a non ambiguous, nonconflicting set of constraints for the view.
By default, the property is set to YES for any view you programmatically create. If you add views in Interface Builder, the system automatically sets this property to NO.
如果属性值是YES,重复被view的autoresizing mask指定的行为。也就是让你通过frame、bound或center等属性来修改视图的size和location,允许您用auto layout创建静态,框架布局。
注意autoresizing mask约束完全指定视图的size和position;因此,你在不引入冲突的情况下不能添加额外约束来修改size或者position(言外之意,属性设置YES,只要修改size或者position就会带来冲突)。如果你想要使用Auto Layout来动态的计算你视图的size和position,你必须设置此属性为NO,并且提供一系列不模棱两可的,无冲突的的视图约束。
编程方式创建视图,属性默认值是YES。如果在IB中添加views,系统自动设置属性为NO.
所以如果是动态计算size和position,就需要设置属性值是NO,之后的button也会将此属性设置为NO。
3.一定要先addSubView:,才能设置一系列的约束,否则一定会报错
4.通过for的方式添加button,添加的button也不需要设置frame,因为在设置translatesAutoresizingMaskIntoConstraints为NO时,button会自动根据内容设置其它的大小
但在内容约束的基础上,我们往往希望内别逗挤在一起,所以在此处设置了内容约束基础上扩宽10PX,你可以按照自己喜好设置
5.然后,其实第一个button是有点不太一样的,它的几何约束是以scrollView为基础的,而剩下的button都是以前面的button为基础,具体你可以参照代码
6.layoutIfNeeded的应用,其中,使用这个属性的话,就自动布局,最明显的反应就是frame值不是0了,在下面也有很好的使用
7.接下来auto layout 约束scrollview,然后设置它的contentSize,其中主要利用了最后一个button的frame值
flipBar大概就是这样
对代码做了一些改进后的demo地址:https://github.com/xiujiePei/PXJSlidButtonBar