87620

How to detect a touch in a subview that was dragged there (or fastest way to get which subview is un

Question:

I've got a Super View, and its got a bunch of subviews. I'd like a user to be able to drag their finger inside the super view and when they drag over the subviews, that subview changes.

I need this to be very efficient, because changes can happen really fast.

So far what i've tried, is in the super view I can get the touch events from touchesBegan:withEvent: and touchesMoved:withEvent: These two combined give me all the touches I need. On each call of these methods, I have to iterate through all of the subviews and test like so

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

Then change that view however I want to. Problem is, from my benchmarking this process is just two slow.

My immediate thought is to have the subview's themselves detect the touch and then just post a notification or something like that when they are tapped. This way I don't have to iterate through them all inside the superview every freaking touch event.

The problem I am encountering with this, is that I haven't found a way to get the subviews themselves to detect that they are touched when they are just dragged over and the touch actually originated on a different UIView.

I'm open to any suggestions that either speed up the first process, or have a different way to accomplish this.

Answer1:

Since your subviews are on a Grid and if they are equally sized, you should be able to calculate the highlighted one directly. You just need to store their references on creation in a 2D array, for performance I suggest to use a c-array.

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

Depending on your Layout, some border margins or spacings between the views should be taken into account.

This way you do not need to iterate the subviews array and you do not need to perform all these CGRectContainsPoint calculations.

Answer2:

Should be easy:

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

Of course, for you, just get rid of the populateView method. I'm just using it to demonstrate how this works as a drop-in class.

If you're looking for speed, then subclass UIView and do this: 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

Then MyViewController.m becomes much simpler and faster:

#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

Recommend

  • Calculating the Determinant in C++
  • insert multiple record to a table with codeigniter
  • Segmentation fault 11, python hash with lists, hashing 1 million objects
  • How to add additional data with data read from a node stream in read callback handler?
  • Handling events from wxTextCtrl on wxFrame - C++/wxWidgets
  • Merge two dot graphs at a common node in python
  • WKInterfaceSwitch or WKInterfaceButton in a table row — which row was touched?
  • Call a Console App from ASP.NET MVC, but don't want to wait for the response
  • Reading text file in Matlab results in unknown spaces within characters
  • How do determine gutter-width in the sass version of zurbs foundation
  • Associative arrays in javascript
  • Dilemma in deciding how to create CSS for H1, H2, H3 etc
  • Sorting an array of files for rename
  • cross domain javascript
  • Gradle Thrift Plugin by Example
  • Why mat-error not get displayed inside mat-form field in angular material 6 withcustom global valida
  • Unity 5.1 Animator Controller not transitioning
  • Shadows for Instantiated Game Object bug?
  • How to control Trigger state (Pause, Play) using code (not just buttons)
  • How to get file download speed (transfer rate) with php?
  • Jquery UI Sortable, move item automatically
  • Unable to play media with vlc ocx
  • Sending keystrokes/mouse clicks to a Java program with Autohotkey
  • Marklogic : Query response time is very high
  • AJAX Html Editor Extender upload image appearing blank
  • d3 v4 drag and drop with TypeScript
  • How to match http request and response using Jersey ContainerRequestFilter and ContainerResponseFilt
  • JQuery Internet Explorer and ajaxstop
  • Different response to non-authenticated users and AJAX calls
  • Opengl-es onTouchEvents problem or a draw problem? [closed]
  • How to redirect a user to a different server and include HTTP basic authentication credentials?
  • Menu Color Fade on Hover with Jquery
  • Join two tables and save into third-sql
  • Knitr HTML Loop - Some HTML output, some R output
  • Can I make an Android app that runs a web view in Chrome 39?
  • How to model a transition system with SPIN
  • ORA-29908: missing primary invocation for ancillary operator
  • LevelDB C iterator
  • Linking SubReports Without LinkChild/LinkMaster
  • Converting MP3 duration time