轉載自: http://www.cnblogs.com/junhuawang/p/6008536.html?utm_source=itdadao&utm_medium=referral
WWDC12 視訊”最佳做法,掌握自動布局”,涵蓋動畫。它讨論了如何更新限制使用
CoreAnimation
由此可得: 要想用限制設定動畫效果需要在動畫方法中更新布局
//第一種 隻執行一次
[UIView animateWithDuration:0.25 animations:^{
//想要用限制實作動畫需要更新布局
[self.view layoutIfNeeded];//調用layoutIfNeeded 告知頁面布局立刻更新。(系統内部調用layoutSubviews重寫布局)
} completion:^(BOOL finished) {
}];
//第二種
[UIView beginAnimations:nil context:nil];
[UIView setAnimationRepeatCount:10];
[self layoutIfNeeded];//調用更改限制的view 的父視圖的layoutIfNeeded 不要掉自己
[UIView commitAnimations];
兩種方式一個是用在 xib 中加的限制 一個是用Masonry 加的限制 (對限制進行更改都可以實作動畫)
AutoLayout
這是自定義了一個view 裡面放裡一個藍色的lineView
#import "CustomView.h"
#import "Masonry.h"
@interface CustomView ()
@property (weak, nonatomic) IBOutlet UILabel *label;
@property (weak, nonatomic) IBOutlet UIView *lineView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *lineCenterConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *lineTopConstraint;
@end
@implementation CustomView
+ (instancetype)loadCustomView{
return [[[NSBundle mainBundle]loadNibNamed:@"CustomView" owner:nil options:nil]firstObject];
}
//注意constraint是限制限制 constant是常數
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//1.先更改限制 (y = kx + b b是常數 (constant) 基于中心的0 負數是減 整數是加)
self.lineCenterConstraint.constant = -self.frame.size.width/4;
self.lineTopConstraint.constant = 70;
//2.在動畫中更改布局
[UIView animateWithDuration:1.0 animations:^{
self.lineView.transform = CGAffineTransformRotate(self.lineView.transform, M_PI);
[self layoutIfNeeded];//調用更改限制的view 的父視圖的layoutIfNeeded 不要掉自己self.lineView
} completion:^(BOOL finished) {
}];
// [UIView beginAnimations:nil context:nil];
// [UIView setAnimationRepeatCount:10];
// [self layoutIfNeeded];//調用更改限制的view 的父視圖的layoutIfNeeded 不要掉自己self.lineView
// self.lineView.transform = CGAffineTransformRotate(self.lineView.transform, M_PI);
// [UIView commitAnimations];
}
運作結果
動畫前
動畫後
第三方架構Masonry
常用方法
// 設定限制 初次設定限制使用
(NSArray *)mas_makeConstraints
// 更改限制 更新mas_makeConstraints裡面的限制使用
(NSArray *)mas_updateConstraints
// 重新設定限制 先移除所有限制,再新增限制
(NSArray *)mas_remakeConstraints
常用屬性
自适應布局允許将寬度或高度設定為固定值.如果你想要給視圖一個最小或最大值,你可以這樣:
//width >= 200 && width <= 400
make.width.greaterThanOrEqualTo(@200);
make.width.lessThanOrEqualTo(@400)
限制的優先級
.priority允許你指定一個精确的優先級,數值越大優先級越高.最高1000.
.priorityHigh等價于 UILayoutPriorityDefaultHigh .優先級值為 750.
.priorityMedium介于高優先級和低優先級之間,優先級值在 250~750之間.
.priorityLow等價于 UILayoutPriorityDefaultLow , 優先級值為 250.
優先級可以在限制的尾部添加:
make.left.greaterThanOrEqualTo(label.mas_left).with.priorityLow();
make.top.equalTo(label.mas_top).with.priority(600);
center 中心
//使 make 的centerX和 centerY = button1
make.center.equalTo(button1)
//使make的 centerX = superview.centerX - 5, centerY = superview.centerY + 10 make.center.equalTo(superview).centerOffset(CGPointMake(-5, 10))
指定寬度為父視圖的 1/4.
make.width.equalTo(superview).multipliedBy(0.25);
鍵盤彈出動畫
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
__weak typeof(self) weakSelf = self;
_textField = [UITextField new];
_textField.backgroundColor = [UIColor redColor];
[self.view addSubview:_textField];
[_textField mas_makeConstraints:^(MASConstraintMaker *make) {
//left,right,centerx,y 不能共存隻能有其二
make.left.mas_equalTo(20);
// make.right.mas_equalTo(-60);
make.centerX.equalTo(weakSelf.view);
make.height.mas_equalTo(40);
make.bottom.mas_equalTo(0);
}];
// 注冊鍵盤通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrameNotification:) name:UIKeyboardWillChangeFrameNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHideNotification:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillChangeFrameNotification:(NSNotification *)notification {
// 擷取鍵盤基本資訊(動畫時長與鍵盤高度)
NSDictionary *userInfo = [notification userInfo];
CGRect rect = [userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGFloat keyboardHeight = CGRectGetHeight(rect);
CGFloat keyboardDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
// 修改下邊距限制
[_textField mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(-keyboardHeight);
}];
// 重新布局
[UIView animateWithDuration:keyboardDuration animations:^{
[self.view layoutIfNeeded];
}];
}
- (void)keyboardWillHideNotification:(NSNotification *)notification {
// 獲得鍵盤動畫時長
NSDictionary *userInfo = [notification userInfo];
CGFloat keyboardDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
// 修改為以前的限制(距下邊距0)
[_textField mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(0);
}];
// 重新布局
[UIView animateWithDuration:keyboardDuration animations:^{
[self.view layoutIfNeeded];
}];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self.view endEditing:YES];
}
以上是動畫 下面是用masony三控件等寬間距(xib 加限制的方式還沒有找到合适的)
假設有多個View,我們需要對其尺寸做批量設定
NSValue *sizeValue = [NSValue valueWithCGSize:CGSizeMake(100, 50)];
[@[view1,view2,view3] mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(sizeValue);
}];
用masony三控件等寬間距
方法一和方法二都在 NSArray+MASAdditions
中
方法一:
array 的 mas_distributeViewsAlongAxis withFixedSpacing
變化的是控件的長度或寬度 間距不變
定義一個存放三個控件的數組
NSArray *array;
array = @[greenView,redView,blueView];
注意:
數組裡面的元素不能小于1個,要不會報錯
views to distribute need to bigger than one
- (void)getHorizontalone
{
//方法一,array 的 mas_distributeViewsAlongAxis
/**
* 多個控件固定間隔的等間隔排列,變化的是控件的長度或者寬度值
*
* @param axisType 軸線方向
* @param fixedSpacing 間隔大小
* @param leadSpacing 頭部間隔
* @param tailSpacing 尾部間隔
*/
// MASAxisTypeHorizontal 水準
// MASAxisTypeVertical 垂直
[arrayList mas_distributeViewsAlongAxis:MASAxisTypeHorizontal
withFixedSpacing:20
leadSpacing:5
tailSpacing:5];
[arrayList mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(60);
make.height.mas_equalTo(100);
}];
方法二
array 的 mas_distributeViewsAlongAxis withFixedItemLength
控件size不變,變化的是間隙
// 豎直方向高度不變60 寬度左邊右邊20 間距變
- (void)getVertical
{
/**
* 多個固定大小的控件的等間隔排列,變化的是間隔的空隙
*
* @param axisType 軸線方向MASAxisTypeVertical 這時候withFixedItemLength是固定高度
* @param fixedItemLength 每個控件的固定長度或者寬度值
* @param leadSpacing 頭部間隔
* @param tailSpacing 尾部間隔
*/
[arrayList mas_distributeViewsAlongAxis:MASAxisTypeVertical
withFixedItemLength:60
leadSpacing:40
tailSpacing:10];
[arrayList mas_makeConstraints:^(MASConstraintMaker *make) {
// make.top.mas_equalTo(100);
// make.height.mas_equalTo(100);
make.left.mas_equalTo(20);
make.right.mas_equalTo(-20);
}];
方法三 :直接設定
multiplier
實作等間距
for (NSUInteger i = 0; i < 4; i++) {
UIView *itemView = [self getItemViewWithIndex:i];
[_containerView addSubview:itemView];
[itemView mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.and.height.equalTo(@(ITEM_SIZE));
make.centerY.equalTo(_containerView.mas_centerY);
make.centerX.equalTo(_containerView.mas_right).multipliedBy(((CGFloat)i + 1) / ((CGFloat)ITEM_COUNT + 1));
}];
}
方法四: 利用透明等寬度的SpaceView實作等間距
UIView *lastSpaceView = [UIView new];
lastSpaceView.backgroundColor = [UIColor greenColor];
[_containerView1 addSubview:lastSpaceView];
[lastSpaceView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.and.top.and.bottom.equalTo(_containerView1);
}];
for (NSUInteger i = 0; i < ITEM_COUNT; i++) {
UIView *itemView = [self getItemViewWithIndex:i];
[_containerView1 addSubview:itemView];
[itemView mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.and.width.equalTo(@(ITEM_SIZE));
make.left.equalTo(lastSpaceView.mas_right);
make.centerY.equalTo(_containerView1.mas_centerY);
}];
UIView *spaceView = [UIView new];
spaceView.backgroundColor = [UIColor greenColor];
[_containerView1 addSubview:spaceView];
[spaceView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(itemView.mas_right).with.priorityHigh(); // 降低優先級,防止寬度不夠出現限制沖突
make.top.and.bottom.equalTo(_containerView1);
make.width.equalTo(lastSpaceView.mas_width);
}];
lastSpaceView = spaceView;
}
[lastSpaceView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(_containerView1.mas_right);
}];
項目中還沒有用到(一般這些方法都是重寫然後再調用super 方法 然後在寫一些其他的操作)
更新限制的方法 在view中
setNeedsUpdateConstraints:告知需要更新限制,但是不會立刻開始
updateConstraintsIfNeeded:告知立刻更新限制
updateConstraints:系統更新限制
在viewController 中
- (void)updateViewConstraints ;
ViewController的View在更新視圖布局時,會先調用ViewController的updateViewConstraints 方法。
我們可以通過重寫這個方法去更新目前View的内部布局,而不用再繼承這個View去重寫-updateConstraints方法。我們在重寫這個方法時,務必要調用 super 或者 調用目前View的 -updateConstraints 方法。