![](/img/trans.png)
[英]How restrict a subview(which is a UIImageView) totally in its superview?
[英]How to detect a touch in a subview that was dragged there (or fastest way to get which subview is underneath a tap in its superview)
我有一个超级视图,并且有很多子视图。 我希望用户能够在超级视图内拖动其手指,并且当他们在子视图上拖动时,该子视图会发生变化。
我需要这样做非常有效,因为更改可以很快发生。
到目前为止,我尝试过的是,在超级视图中,我可以从touchesBegan:withEvent:和touchesMoved:withEvent中获取触摸事件:这两个结合在一起为我提供了我需要的所有触摸。 每次调用这些方法时,我都必须遍历所有子视图并像这样进行测试
for (UIView *view in self.subviews) {
if (CGRectContainsPoint(view.frame, touchPoint) {
return view;
}
}
然后根据需要更改该视图。 问题是,根据我的基准测试,此过程只有两个过程。
我立即想到的是让子视图本身检测到触摸,然后在点击时发布通知或类似内容。 这样,我不必在每个异常的触摸事件中都遍历超级视图中的所有对象。
我遇到的问题是,我还没有找到一种方法来获取子视图本身,以检测它们是否在被拖动并且触摸实际上源自其他UIView时被触摸了。
我愿意接受任何建议来加快第一个过程,或者采用其他方法来完成此过程。
由于子视图位于网格上,并且如果它们的大小相等,那么您应该能够直接计算突出显示的子视图。 您只需要在创建时将它们的引用存储在2D数组中,为获得性能,我建议使用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
方法即可。 我只是用它来演示它作为嵌入式课程的工作方式。
如果您正在寻找速度,请子类化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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.