动态/可拖动UIView的自动布局

时间:2013-10-16 08:35:23

标签: ios objective-c uiview constraints autolayout

我试图在我的ViewController中有一个可拖动的UIView,最终这个UIView将成为一个可点击的按钮但是现在,当它被拖动到屏幕上时,我仍然坚持更新该视图的约束。代码如下。

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.anotherView = [[UIView alloc]init];
    UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(dragging:)];
    [self.anotherView addGestureRecognizer:panRecognizer];
    [self.anotherView setBackgroundColor: [UIColor blueColor]];
    self.anotherView.translatesAutoresizingMaskIntoConstraints = NO;

    [self.view addSubview: self.anotherView];
    [self.view bringSubviewToFront:self.anotherView];

    NSDictionary *views = @{@"subview" : self.anotherView, @"superview" : self.view};

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.anotherView
                                                          attribute:NSLayoutAttributeLeft
                                                          relatedBy:NSLayoutRelationLessThanOrEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeLeft
                                                         multiplier:1.0
                                                           constant:0]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.anotherView
                                                          attribute:NSLayoutAttributeCenterY
                                                          relatedBy:NSLayoutRelationLessThanOrEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeCenterY
                                                         multiplier:1.0
                                                           constant:0]];


    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.anotherView
                                                          attribute:NSLayoutAttributeWidth
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:Nil
                                                          attribute:NSLayoutAttributeWidth
                                                         multiplier:1.0
                                                           constant:20]];

    [self.view addConstraints:[NSLayoutConstraint
                               constraintsWithVisualFormat:@"V:[subview(40)]"
                               options:0
                               metrics:nil
                               views:views]];
        // add horizontal constraints

    /*[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview(==20)]|" options:0 metrics:nil views:views]];

     // set the height of the offscreen subview to be the same as its superview

     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[subview(==40)]" options:0 metrics:nil views:views]];

     // set the location of the subview to be just off screen below the current view

     NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.anotherView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationLessThanOrEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:1.0 constant:self.view.bounds.size.height];
     [self.view addConstraint:constraint];*/
        //[self.anotherView pinEdges:JRTViewPinLeftEdge toSameEdgesOfView:self.view];


        // Do any additional setup after loading the view, typically from a nib.
    self.navigationItem.leftBarButtonItem = self.editButtonItem;

    UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)];
    self.navigationItem.rightBarButtonItem = addButton;
    self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
}

以上代码是我在ViewController中设置UIView的方法。预计尺寸为20x45。拖动代码如下:

-(void)dragging:(UIPanGestureRecognizer *)gesture
{
    if(gesture.state == UIGestureRecognizerStateBegan)
        {
            //NSLog(@"Received a pan gesture");
        self.panCoord = [gesture locationInView:gesture.view];
        [self.tableView setScrollEnabled:NO];

        }
    CGPoint newCoord = [gesture locationInView:gesture.view];
    float dX = newCoord.x-self.panCoord.x;
    float dY = newCoord.y-self.panCoord.y;
    CGFloat newXPoint;
    CGFloat newYPoint;

    gesture.view.frame = CGRectMake(gesture.view.frame.origin.x+dX, gesture.view.frame.origin.y+dY, gesture.view.frame.size.width, gesture.view.frame.size.height);
    if (gesture.state == UIGestureRecognizerStateEnded) {
        newYPoint = gesture.view.frame.origin.y+dY;
        if (gesture.view.frame.origin.x+dX<(self.view.frame.size.width/2)) {
            newXPoint = 0;
        }
        else {
            newXPoint = self.view.frame.size.width - gesture.view.frame.size.width;
//The below is just an attempt to remove and re-add constraints so the view will stick to the right side of the screen. It is not working :( 
            [self.view removeConstraint:[NSLayoutConstraint constraintWithItem:self.anotherView
                                                                  attribute:NSLayoutAttributeLeft
                                                                  relatedBy:NSLayoutRelationLessThanOrEqual
                                                                     toItem:self.view
                                                                  attribute:NSLayoutAttributeLeft
                                                                 multiplier:1.0
                                                                   constant:0]];

            [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.anotherView
                                                                  attribute:NSLayoutAttributeRight
                                                                  relatedBy:NSLayoutRelationLessThanOrEqual
                                                                     toItem:self.view
                                                                  attribute:NSLayoutAttributeRight
                                                                 multiplier:1.0
                                                                   constant:0]];


        }


            //        self.draggedViewCoordinate = gesture.view.frame.origin;

        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:0.70];
        [UIView setAnimationDelay:0.0];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
        [self.anotherView layoutIfNeeded];
        [UIView commitAnimations];
        [self.tableView setScrollEnabled:YES];
    }

}

我没有得到如何更新约束,因此视图将坚持新的拖动位置。任何人都可以帮忙吗?

3 个答案:

答案 0 :(得分:9)

接受的答案不正确。 UI添加/删除约束的操作非常昂贵。 正确的解决方案将会改变

self.yCoordinate.constant

self.xCoordinate.constant

基于dX和dY的属性。

答案 1 :(得分:2)

好的,我用下面的代码解决了它!

-(void)dragging:(UIPanGestureRecognizer *)gesture
{
    if(gesture.state == UIGestureRecognizerStateBegan)
        {
            //NSLog(@"Received a pan gesture");
        self.panCoord = [gesture locationInView:gesture.view];
        [self.tableView setScrollEnabled:NO];

        }
    CGPoint newCoord = [gesture locationInView:gesture.view];
    float dX = newCoord.x-self.panCoord.x;
    float dY = newCoord.y-self.panCoord.y;
    CGFloat newXPoint;
    CGFloat newYPoint;
    gesture.view.frame = CGRectMake(gesture.view.frame.origin.x+dX, gesture.view.frame.origin.y+dY, gesture.view.frame.size.width, gesture.view.frame.size.height);
    if (gesture.state == UIGestureRecognizerStateEnded) {
        newYPoint = gesture.view.frame.origin.y+dY;
        CGFloat newYPosition = (self.view.frame.size.height/2) - newYPoint - 20;
        if (gesture.view.frame.origin.x+dX<(self.view.frame.size.width/2)) {
            [self.view removeConstraint:self.xCoordinate];
            [self.view removeConstraint:self.yCoordinate];

            self.xCoordinate = [NSLayoutConstraint constraintWithItem:self.anotherView
                                                            attribute:NSLayoutAttributeLeft
                                                            relatedBy:NSLayoutRelationLessThanOrEqual
                                                               toItem:self.view
                                                            attribute:NSLayoutAttributeLeft
                                                           multiplier:1.0
                                                             constant:0];

            [self.view addConstraint:self.xCoordinate];

            self.anotherView.translatesAutoresizingMaskIntoConstraints = NO;

            self.yCoordinate = [NSLayoutConstraint constraintWithItem:self.anotherView
                                                            attribute:NSLayoutAttributeCenterY
                                                            relatedBy:NSLayoutRelationEqual
                                                               toItem:self.view
                                                            attribute:NSLayoutAttributeCenterY
                                                           multiplier:1.0
                                                             constant:-newYPosition];
            [self.view addConstraint:self.yCoordinate];

        }
        else {
            newXPoint = self.view.frame.size.width - gesture.view.frame.size.width;


            [self.view removeConstraint:self.xCoordinate];
            [self.view removeConstraint:self.yCoordinate];

            self.xCoordinate = [NSLayoutConstraint constraintWithItem:self.anotherView
                                                            attribute:NSLayoutAttributeRight
                                                            relatedBy:NSLayoutRelationLessThanOrEqual
                                                               toItem:self.view
                                                            attribute:NSLayoutAttributeRight
                                                           multiplier:1.0
                                                             constant:0];

            [self.view addConstraint:self.xCoordinate];

            self.anotherView.translatesAutoresizingMaskIntoConstraints = NO;

            self.yCoordinate = [NSLayoutConstraint constraintWithItem:self.anotherView
                                                            attribute:NSLayoutAttributeCenterY
                                                            relatedBy:NSLayoutRelationEqual
                                                               toItem:self.view
                                                            attribute:NSLayoutAttributeCenterY
                                                           multiplier:1.0
                                                             constant:-newYPosition];
            [self.view addConstraint:self.yCoordinate];



        }


            //        self.draggedViewCoordinate = gesture.view.frame.origin;

        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:0.70];
        [UIView setAnimationDelay:0.0];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
        [self.anotherView layoutIfNeeded];
                //        gesture.view.frame = CGRectMake(newXPoint, newYPoint, gesture.view.frame.size.width, gesture.view.frame.size.height);
        [UIView commitAnimations];

        [self.tableView setScrollEnabled:YES];
    }

}

基本上,我保留了对约束的引用。这有助于我根据拖动视图的位置删除/重新添加约束。

答案 2 :(得分:1)

这个简化版本在向下和向下拖动时为我解决了:

@implementation SomeController
{
    float beginDragPointY;
    NSLayoutConstraint someConstraint;
}
- (void) viewDidLoad
{
    // Define someConstraint 
}

- (void) onDragGesture: (id) sender
{
    UIPanGestureRecognizer* recognizer = (UIPanGestureRecognizer*)sender;
    UIGestureRecognizerState state = recognizer.state;
    CGPoint translation = [sender translationInView:self.view];

    switch(state)
    {
        case UIGestureRecognizerStateBegan:
            NSLog(@"Translation began %f %f", translation.x, translation.y);
            beginDragPointY = translation.y;
        break;

        case UIGestureRecognizerStateChanged:
            showBasicEventAnnotationConstraint.constant += translation.y - beginDragPointY;
            beginDragPointY = translation.y;
            [self.view setNeedsLayout];
        break;
        case UIGestureRecognizerStateEnded:
        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateFailed:
        case UIGestureRecognizerStatePossible:
        default:
            break;
    }

    [self.view layoutIfNeeded];
}