两个视图交易布局动画(包括Z Order)

时间:2015-04-15 17:44:57

标签: ios objective-c animation nslayoutconstraint

我有两个视图,一个是UIImageView,用于显示用户选择的照片,另一个是MKMapKitView,用于显示用户选择的对象位置。在休息时,视图的排列如下:

enter image description here

当用户点击视图2时,我希望两者改变位置。反之亦然。两个视图都有约束条件。所以我可以做一个动画,我首先获取两组约束,然后清除它们,然后按翻转顺序应用它们,但是z顺序不会切换。无论哪种观点都在"小"模式应该远远超过另一个。

我真的希望能够设置它的动画,以便交换显而易见。不知何故,通过执行以下操作使其显示为旋转:

enter image description here

实现这一目标的最简单方法是什么?我尝试了以下方法:

- (IBAction)swapPreview {
    NSArray *photoConstraints = self.photoView.constraints;
    NSArray *mapConstraints = self.mapView.constraints;
    [self.photoView removeConstraints: photoConstraints];
    [self.mapView removeConstraints: mapConstraints];
    NSLog(@"photoConstraints %@", photoConstraints);
    NSLog(@"mapConstraints %@", mapConstraints);
    CGRect biggerFrame = CGRectUnion(self.photoView.frame, self.mapView.frame);
    CGRect upperFrame = CGRectOffset(RectCenterScaled(biggerFrame, 0.5), 0, biggerFrame.size.height / -4);
    CGRect lowerFrame = CGRectOffset(upperFrame, 0, upperFrame.size.height);
    [UIView animateWithDuration: 0.4 delay: 0 options: UIViewAnimationOptionCurveLinear animations:^{
        self.photoView.frame = upperFrame;
        self.mapView.frame = lowerFrame;
    } completion:^(BOOL finished) {
        UIView *container = self.photoView.superview;
        [self.photoView addConstraints: mapConstraints];
        [self.mapView addConstraints: photoConstraints];
        [container exchangeSubviewAtIndex: [container.subviews indexOfObject: self.photoView] withSubviewAtIndex:[container.subviews indexOfObject: self.mapView]];
        [UIView animateWithDuration: 0.4 delay: 0 options: UIViewAnimationOptionCurveLinear animations:^{
            [container updateConstraints];
        } completion:^(BOOL finished) {

        }];
    }];
}

但是当我尝试交换约束时,这会破坏第二个动画块。那么更好的方法是什么?我可以遍历视图层次结构中的所有约束,交换任何引用这两个视图的firstItem / secondItems。但是较小视图的局部约束需要改变局部性。

我开始怀疑自己是不是应该制作一个有两个孩子的自定义UIView子类并直接进行布局,而不是搞乱约束。

2 个答案:

答案 0 :(得分:1)

我制作了符合你想要的测试项目和课程:

@interface ViewController ()
                                                                  //initial constants values
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *view1Top;//0
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *view2Top;//20
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *view1Left;//0
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *view2Left;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *view1Height;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *view2Height;//100
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *view1Width;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *view2Width;//50
@property (weak, nonatomic) IBOutlet UIView *view1;
@property (weak, nonatomic) IBOutlet UIView *view2;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

}
- (void)viewWillAppear:(BOOL)animated{
    //setting initial values for constraints related to view size
    self.view1Width.constant = self.self.view.frame.size.width;
    self.view1Height.constant = self.self.view.frame.size.height;
    self.view2Left.constant = self.view.frame.size.width - 20 - self.view2Width.constant;
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
- (IBAction)animate:(id)sender {

    CGFloat gap = 20.0;
    CGFloat height = (self.view.frame.size.height - 3*gap)/2; //height of views in the middle of animation
    CGFloat width = self.view.frame.size.width - 40; //width of views in the middle of animation
    self.view1Top.constant = gap;
    self.view1Height.constant = height;
    self.view2Top.constant = height + 2*gap;
    self.view2Height.constant = height;
    self.view1Left.constant = self.view2Left.constant = gap;
    self.view1Width.constant = self.view2Width.constant = width;

     [UIView animateWithDuration:4.0 delay:0 options:0 animations:^{
         [self.view layoutIfNeeded];
             } completion:^(BOOL finished) {

         [self.view exchangeSubviewAtIndex: [self.view.subviews indexOfObject: self.view1] withSubviewAtIndex:[self.view.subviews indexOfObject: self.view2]];
                 self.view2Top.constant = 0;
                 self.view2Left.constant = 0;
                 self.view2Height.constant = self.view.frame.size.height;
                 self.view2Width.constant = self.view.frame.size.width;

                 self.view1Top.constant = gap;
                 self.view1Width.constant = 50;
                 self.view1Height.constant = 100;
                 self.view1Left.constant = self.view.frame.size.width - self.view1Width.constant - gap;

         [UIView animateWithDuration:4.0 animations:^{
             [self.view layoutIfNeeded];
                    }];

     }];
}

@end

view1 是红色视图, view2 是蓝色视图。

animate 是我的案例中由按钮点按启动的一个动作。

关键不是仅仅为动画常量属性移除约束。

答案 1 :(得分:0)

UIView提供以下内容:

- (void)bringSubviewToFront:(UIView *)view;
- (void)sendSubviewToBack:(UIView *)view;

控制视图的Z顺序。

使用其中一个动画的完成块。这样做的好时机是观点不重叠。