如何在被拖动的子视图中检测触摸(或者在其超级视图中获取哪个子视图下方的最快方式)

我有一个超级视图,它有一堆子视图。 我希望用户能够在超级视图中拖动手指,当他们拖动子视图时,该子视图会发生变化。

我需要这样做非常有效率,因为变化可以发生得非常快。

到目前为止,我所尝试的是,在超级视图中,我可以从touchesBegan:withEvent:和touchesMoved:withEvent获取触摸事件:这两个组合给了我所需要的所有触摸。 在每次调用这些方法时,我都必须遍历所有子视图并像这样testing

for (UIView *view in self.subviews) { if (CGRectContainsPoint(view.frame, touchPoint) { return view; } } 

然后改变那个观点,但我想。 问题是,从我的基准testing来看,这个过程只是两个缓慢的过程。

我的直接想法是让子视图自己检测触摸,然后只是发布通知或类似的东西,当他们被挖掘。 这样我就不用在superview里面遍历每一个奇怪的触摸事件。

我遇到的问题是,我还没有find一种方式来获取子视图自己来检测,当他们只是拖动,触摸实际上是源于不同的UIView时,他们被触摸。

我接受任何加快第一个stream程的build议,或者有不同的方法来完成这个任务。

由于您的子视图位于网格上,如果它们的大小相同,则应该能够直接计算高亮显示的一个。 你只需要将其创build的参考存储在二维数组中,为了提高性能,我build议使用一个c数组。

 int x = touchPoint.x/viewWidth; int y = touchPoint.y/viewHeight; return views[x][y]; 

根据您的布局,应考虑视图之间的边界或间距。

这样你就不需要遍历子视图数组,你不需要执行所有这些CGRectContainsPoint计算。

应该很容易:

MyViewController.h

 #import <UIKit/UIKit.h> @interface MyViewController : UIViewController @end 

MyViewController.m

 #import "MyViewController.h" #define SIDE_LENGTH 60 #define NUM_SQUARES 15 @implementation MyViewController { UIView *_selectedView; } - (void)viewDidLoad { [super viewDidLoad]; [self populateView]; } - (void)populateView { for (int i = 0; i < 15; ++i) { CGRect frame = CGRectMake(drand48() * self.view.frame.size.width - SIDE_LENGTH, drand48() *self.view.frame.size.height - SIDE_LENGTH, SIDE_LENGTH, SIDE_LENGTH); UIView *view = [[UIView alloc] initWithFrame:frame]; view.backgroundColor = [UIColor colorWithRed:drand48() green:drand48() blue:drand48() alpha:1.0f]; view.layer.cornerRadius = SIDE_LENGTH / 2.0f; // cuz circles r pretty [self.view addSubview:view]; } } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self.view]; for (UIView *view in self.view.subviews) { if (CGRectContainsPoint(view.frame, location)) { _selectedView = view; break; } } } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self.view]; _selectedView.center = location; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self.view]; _selectedView.center = location; } @end 

当然,对于你来说,只是摆脱populateView方法。 我只是用它来演示这是如何工作的一个下拉class。

如果你正在寻找速度,然后子类UIView并执行此操作:MyView.h

 #import <UIKit/UIKit.h> @class MyView; @interface MyView : UIView @end 

MyView.m

 @implementation MyView - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self.superview]; self.center = location; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self.superview]; self.center = location; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self.superview]; self.center = location; } @end 

然后MyViewController.m变得更简单和更快:

 #import "MyViewController.h" #import "MyView.h" #define SIDE_LENGTH 60 #define NUM_SQUARES 15 @implementation MyViewController { UIView *_selectedView; } - (void)viewDidLoad { [super viewDidLoad]; [self populateView]; } - (void)populateView { for (int i = 0; i < 15; ++i) { CGRect frame = CGRectMake(drand48() * self.view.frame.size.width - SIDE_LENGTH, drand48() *self.view.frame.size.height - SIDE_LENGTH, SIDE_LENGTH, SIDE_LENGTH); MyView *view = [[MyView alloc] initWithFrame:frame]; view.backgroundColor = [UIColor colorWithRed:drand48() green:drand48() blue:drand48() alpha:1.0f]; view.layer.cornerRadius = SIDE_LENGTH / 2.0f; [self.view addSubview:view]; } } @end