![](/img/trans.png)
[英]Dragging UIView with UIAttachmentBehavior and auto layout constraints
[英]Dragging views using UIAttachmentBehavior
我想拖動一個UIView,讓它移動附加到其上的其他視圖的位置,就像它們都是通過字符串連接一樣。 起始狀態將是一堆UIViews聚集在一起。 如果你拉出一個項目,它附加的項目將在它與被拖動的視圖之間達到最小距離后開始移動。 我認為實現這一目標的最佳方法是使用UIDynamicItemBehavior,考慮到我需要將其重新捕捉到適當位置並對其施加權重。 如果不做荒謬的代碼,我不太清楚如何實現這一點。 我所擁有的代碼可以在下面看到。 不幸的是,我遇到的問題是被拖動的方形項目回到了square2。 如果有人有任何建議,我會很樂意澄清是否需要。
- (void)viewDidLoad
{
[super viewDidLoad];
_containmentView = [[UIView alloc] initWithFrame:CGRectMake(0.0, self.view.frame.size.height/2, self.view.frame.size.width, 200)];
[self.view addSubview:_containmentView];
[_containmentView setBackgroundColor:[UIColor greenColor]];
_square = [[UIView alloc]initWithFrame:CGRectMake(200, 0, 100, 100)];
_square.backgroundColor = [UIColor yellowColor];
[_containmentView addSubview:_square];
_square2 = [[UIView alloc]initWithFrame:CGRectMake(100, 0, 100, 100)];
_square2.backgroundColor = [UIColor redColor];
[_containmentView addSubview:_square2];
_animator = [[UIDynamicAnimator alloc]initWithReferenceView:_containmentView];
_gravity = [[UIGravityBehavior alloc]initWithItems:@[_square, _square2]];
_gravity.gravityDirection = CGVectorMake(-1.0, 0.0);
[_animator addBehavior:_gravity];
_collision = [[UICollisionBehavior alloc]initWithItems:@[_square]];
_collision.collisionDelegate = self;
_collision.translatesReferenceBoundsIntoBoundary = YES; //causes the boundary to use the bounds of the reference view supplied to the UIDynamicAnimator
[_animator addBehavior:_collision];
UIDynamicItemBehavior *itemBehaviour = [[UIDynamicItemBehavior alloc] initWithItems:@[_square]];
itemBehaviour.elasticity = 0.6;
[_animator addBehavior:itemBehaviour];
UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[_square addGestureRecognizer:gesture];
UIAttachmentBehavior *attach = [[UIAttachmentBehavior alloc] initWithItem:_square2 attachedToItem:_square];
[_animator addBehavior:attach];
}
-(void)handlePan:(UIPanGestureRecognizer *)gesture
{
CGPoint touchPoint = [gesture locationInView:self.view];
UIView* draggedView = gesture.view;
if (gesture.state == UIGestureRecognizerStateBegan) {
// 1. was the pan initiated from the upper part of the recipe?
UIView* draggedView = gesture.view;
CGPoint dragStartLocation = [gesture locationInView:draggedView];
_draggingView = YES;
_previousTouchPoint = touchPoint;
// [_animator updateItemUsingCurrentState:draggedView];
} else if (gesture.state == UIGestureRecognizerStateChanged && _draggingView) {
// 2. handle dragging
float xOffset = _previousTouchPoint.x - touchPoint.x;
gesture.view.center = CGPointMake(draggedView.center.x - xOffset,
draggedView.center.y);
_previousTouchPoint = touchPoint;
// [_animator updateItemUsingCurrentState:draggedView];
} else if (gesture.state == UIGestureRecognizerStateEnded && _draggingView) {
// 3. the gesture has ended
// [self tryDockView:draggedView];
// [self addVelocityToView:draggedView fromGesture:gesture];
[_animator updateItemUsingCurrentState:draggedView];
_draggingView = NO;
}
}
您需要使用附件拖動您的形狀,因此動畫師可以使用其物理引擎計算每個項目位置。
這是你viewDidLoad更新:
- (void)viewDidLoad
{
[super viewDidLoad];
_containmentView = [[UIView alloc] initWithFrame:CGRectMake(0.0, self.view.frame.size.height/2, self.view.frame.size.width, 200)];
[self.view addSubview:_containmentView];
[_containmentView setBackgroundColor:[UIColor greenColor]];
_square = [[UIView alloc]initWithFrame:CGRectMake(200, 0, 100, 100)];
_square.backgroundColor = [UIColor yellowColor];
[_containmentView addSubview:_square];
_square2 = [[UIView alloc]initWithFrame:CGRectMake(100, 0, 100, 100)];
_square2.backgroundColor = [UIColor redColor];
[_containmentView addSubview:_square2];
_animator = [[UIDynamicAnimator alloc]initWithReferenceView:_containmentView];
_gravity = [[UIGravityBehavior alloc]initWithItems:@[_square, _square2]];
_gravity.gravityDirection = CGVectorMake(-1.0, 0.0);
[_animator addBehavior:_gravity];
_collision = [[UICollisionBehavior alloc]initWithItems:@[_square, _square2]];
_collision.translatesReferenceBoundsIntoBoundary = YES;
[_animator addBehavior:_collision];
UIDynamicItemBehavior *itemBehaviour = [[UIDynamicItemBehavior alloc] initWithItems:@[_square, _square2]];
itemBehaviour.elasticity = 0.6;
[_animator addBehavior:itemBehaviour];
UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[_square addGestureRecognizer:gesture];
UIPanGestureRecognizer *gesture2 = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[_square2 addGestureRecognizer:gesture2];
UIAttachmentBehavior *attach = [[UIAttachmentBehavior alloc] initWithItem:_square2 attachedToItem:_square];
attach.damping = 1.6;
attach.frequency = 10;
[_animator addBehavior:attach];
}
我為這兩種形狀添加了重力,平移和碰撞。
這里應該看看你的handlePan方法:
-(void)handlePan:(UIPanGestureRecognizer *)gesture
{
CGPoint touchPoint = [gesture locationInView:_containmentView];
UIView* draggedView = gesture.view;
if (gesture.state == UIGestureRecognizerStateBegan) {
// 1. was the pan initiated from the upper part of the recipe?
_draggingView = YES;
_previousTouchPoint = touchPoint;
// Add a new attachment on the selected view;
self.attachment = [[UIAttachmentBehavior alloc] initWithItem:draggedView attachedToAnchor:touchPoint];
[self.animator addBehavior:self.attachment];
// Could temporarily remove gravity here
} else if (gesture.state == UIGestureRecognizerStateChanged && _draggingView) {
// 2. handle dragging
[self.attachment setAnchorPoint:touchPoint];
} else if (gesture.state == UIGestureRecognizerStateEnded && _draggingView) {
// 3. the gesture has ended
_draggingView = NO;
[self.animator removeBehavior:self.attachment];
// If gravity was removed, add it back here
}
}
您可能希望在拖動時暫時移除重力。 只需看看我的評論,看看你能做到哪里(並且不要忘記在拖動結束時把它放回去)。
正如您所看到的,您真的需要更少的編碼來處理手勢:)
您可以使用附件的阻尼,頻率和長度來使形狀對拖動手勢做出不同的反應。 您還可以使用UIDynamicItemBehavior的density
屬性為形狀添加density
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.