我有一个 UILabel,我在其中添加了一个平移手势识别器,并且使用 UIImage 视图在我的视图上还有一个垃圾桶图像。每次我将 UILabel 拖到垃圾桶图像时,我都想从我的程序视图中删除 UILabel。
2 回答
我假设你想做这样的事情:
我将向您展示如何实现它。
我们需要一个用于标签的出口和一个用于垃圾桶视图的出口:
@interface ViewController ()
@property (strong, nonatomic) IBOutlet UIImageView *trashView;
@property (strong, nonatomic) IBOutlet UILabel *label;
@end
将这些连接到您的标签和垃圾桶视图。我们还需要两个实例变量:
@implementation ViewController {
CGPoint labelOriginalCenter;
BOOL trashIsShowingPendingDropAppearance;
}
我们需要保存标签的原始位置,以便在取消拖动时将其动画化:
- (void)viewDidLoad {
[super viewDidLoad];
labelOriginalCenter = self.label.center;
}
现在让我们为平移手势识别器执行操作。我们需要根据手势移动标签。然后我们需要根据手势的状态采取行动。
- (IBAction)labelWasDragged:(UIPanGestureRecognizer *)recognizer {
[self moveLabelForDrag:recognizer];
switch (recognizer.state) {
case UIGestureRecognizerStateChanged:
[self labelDragDidChange:recognizer];
break;
case UIGestureRecognizerStateEnded:
[self labelDragDidEnd:recognizer];
break;
case UIGestureRecognizerStateCancelled:
[self labelDragDidAbort:recognizer];
break;
default:
break;
}
}
为了移动标签,我们通过手势的平移来改变它的中心。我们还将手势的平移在每次更改时重置为零。
- (void)moveLabelForDrag:(UIPanGestureRecognizer *)sender {
CGPoint translation = [sender translationInView:self.label];
[sender setTranslation:CGPointZero inView:self.label];
CGPoint center = self.label.center;
center.x += translation.x;
center.y += translation.y;
self.label.center = center;
}
如果手势发生了变化,我们想根据触摸是否在垃圾桶上来更新垃圾桶的外观:
- (void)labelDragDidChange:(UIPanGestureRecognizer *)recognizer {
if ([self dragIsOverTrash:recognizer]) {
[self updateTrashAppearanceForPendingDrop];
} else {
[self updateTrashAppearanceForNoPendingDrop];
}
}
如果手势结束,我们希望根据手势结束时触摸是否在垃圾桶上方来丢弃标签或中止拖动:
- (void)labelDragDidEnd:(UIPanGestureRecognizer *)recognizer {
if ([self dragIsOverTrash:recognizer]) {
[self dropLabelInTrash];
} else {
[self abortLabelDrag];
}
}
如果手势被取消,我们要中止拖动:
- (void)labelDragDidAbort:(UIPanGestureRecognizer *)recognizer {
[self abortLabelDrag];
}
为了检测手势的触摸是否在垃圾桶上,我们向手势识别器询问它在垃圾桶视图坐标系中的位置。然后我们询问垃圾视图该位置是否在垃圾视图的范围内。
- (BOOL)dragIsOverTrash:(UIPanGestureRecognizer *)recognizer {
CGPoint pointInTrash = [recognizer locationInView:self.trashView];
return [self.trashView pointInside:pointInTrash withEvent:nil];
}
我们可以通过许多不同的方式更新垃圾桶的外观。在这里,我们将让垃圾桶在拖拽在垃圾桶上方时摆动:
- (void)updateTrashAppearanceForPendingDrop {
if (trashIsShowingPendingDropAppearance)
return;
trashIsShowingPendingDropAppearance = YES;
self.trashView.transform = CGAffineTransformMakeRotation(-.1);
[UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat animations:^{
self.trashView.transform = CGAffineTransformMakeRotation(.1);
} completion:nil];
}
当拖拽移出垃圾桶时,我们需要让垃圾桶停止摆动:
- (void)updateTrashAppearanceForNoPendingDrop {
if (!trashIsShowingPendingDropAppearance)
return;
trashIsShowingPendingDropAppearance = NO;
[UIView animateWithDuration:0.15 animations:^{
self.trashView.transform = CGAffineTransformIdentity;
}];
}
当我们想将标签放入垃圾箱时,我们需要做几件事。我们需要停止垃圾桶摆动,我们需要将标签动画化到垃圾桶中,当动画结束时,我们需要完全移除标签。
- (void)dropLabelInTrash {
[self updateTrashAppearanceForNoPendingDrop];
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.label.center = self.trashView.center;
self.label.transform = CGAffineTransformMakeScale(0.1, 0.1);
} completion:^(BOOL finished) {
[self.label removeFromSuperview];
self.label = nil;
}];
}
如果拖动被中止,我们需要停止垃圾桶摆动并将标签动画回其原始位置:
- (void)abortLabelDrag {
[self updateTrashAppearanceForNoPendingDrop];
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.label.center = labelOriginalCenter;
} completion:nil];
}
就这样!
标签可以从手势识别器的视图属性中获取。至于垃圾桶,您可以使用 CGRectIntersectsRect 来确定您拖动标签的矩形是否与垃圾桶的矩形重叠。在手势识别器的 action 方法中是这样的:
- (IBAction)handlePan:(UIPanGestureRecognizer *)sender {
// your other panning code here
if (sender.state == UIGestureRecognizerStateEnded){
if (CGRectIntersectsRect(sender.view.frame, trashcanImageView.frame))
[ sender.view removeFromSuperview];
}
}