I am working on an iOS map app and it includes interactive map. The interactive map is a subclass of UIImageView and placed on a scrollView. My view hierarchy is shown below:
When user taps some part of the map, ViewController performs animated segue (like zoom-in to that area of the map). I can start segue from any point of the screen, but to do this properly, I need exact coordinates of user's tap relative to the screen itself. As ImageView is put at the top of ScrollView, it uses different coordinate system, larger than screen size. No matter, which area of map has ben tapped, what matters is the tapped CGPoint on the screen (physical).
ImageView uses its own code to get coordinates of a tap:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
// cancel previous touch ended event
[NSObject cancelPreviousPerformRequestsWithTarget:self];
CGPoint touchPoint = \
[[touches anyObject] locationInView:self];
NSValue* touchValue =\
[NSValue
valueWithCGPoint:touchPoint];
// perform new one
[self
performSelector:#selector(_performHitTestOnArea:)
withObject:touchValue
afterDelay:0.1];
}
And the case if I place gesture recognizer, it works, but ImageView can't get any touches and, therefore, call segue.
The code for gesture recognizer, I attempted to use:
UITapGestureRecognizer *rec = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapRecognized:)];
[someView addGestureRecognizer:rec];
[rec release];
// elsewhere
- (void)tapRecognized:(UITapGestureRecognizer *)recognizer
{
if(recognizer.state == UIGestureRecognizerStateRecognized)
{
CGPoint point = [recognizer locationInView:recognizer.view];
// again, point.x and point.y have the coordinates
}
}
So, is there any way to get two coordinates in different reference systems?, or to make these recognizers work simultaneously without interfering each other?
Solved
I use this code to convert touched point from one view's reference system to
CGPoint pointInViewCoords = [self.parentView convertPoint:self.imageView.touchPoint fromView:self.imageView];
Where self.parentView is "View" on hierarchy image - with the size of the screen.
Related
I am trying to figure out how I can determine if my touchpoint is where I have a UIView as subview or not. The background is UIView itself that I am adding multiple other UIViews to ... So as I long press and am changing the position while holding the touch, I'd like to know if there's a UIView at that point or not.
I have been thinking, still not clear how to go about it but came across this which makes me think of getting the indexes of hierarchy and check of it is larger than 1. But how could I do that for where I'm touching?
Any hint or clue would be appreciated.
You have to store both reference in two objects myParentView and mySubView now just use this method..
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint locationPoint = [[touches anyObject] locationInView: myParentView];
UIView* viewYouWishToObtain = [self hitTest:locationPoint withEvent:event];
if(mySubView == viewYouWishToObtain){
//That view is touched
}else{
//That view is not touched
}
}
I have a UIImageView placed with frame (0,0,320,200).
i have added touch drag to it using simple gesture.
- (void)touchesMoved:(NSSet *)set withEvent:(UIEvent *)event {
CGPoint p = [[set anyObject] locationInView:self.superview];
self.center = p;
}
It works fine, however as soon as i drag it to bottom of screen let's say and remove my finger and then try to touch it, it stops detecting touch on the view and start detecting touch on the views on the screen. Now this imageView is placed on top of all views so i am not sure even its dragged why it doesn't get touches ,
Now if somehow using any button make it move ot its original position it starts detecting touch again.
So whats going on here?
Set up a gestureRecognizer within your viewDidLoad method for example.
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(wasDragged:)];
[YourImageView addGestureRecognizer:panRecognizer];
Once your ImageView has been moved the gestureRecognizer object will fire the target method you created wasDragged: and from within here you can update the view's position.
- (void)wasDragged:(UIPanGestureRecognizer *)recognizer {
UIImagewView *imageView = (UIImagewView *)recognizer.view;
CGPoint translation = [recognizer translationInView:imageView];
imageView.center = CGPointMake(imageView.center.x + translation.x, imageView.center.y + translation.y);
[recognizer setTranslation:CGPointZero inView:imageView];
}
After this has been dragged to the bottom of the screen as you say, you should be able to drag it again from the position you last left it in.
I hope this helps.
In my application I have multiple small views joined together to form a big canvas. Im properly getting the touch begin/moved/ended events for each of those views separately. What I want now is this that if I touch at view1 and drag my finger out of view1 and into the territory of view2 without lifting my finger up, I want the view2 to somehow get a notification that I'm now in this view i.e. view2. Thanks.
I was able to do it using touchesMoved method. Here's the code:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
CGPoint nowPoint = [touches.anyObject locationInView:self.view];
NSLog(#"%f, %f", nowPoint.x, nowPoint.y);
NSArray *viewsToCheck = [self.view subviews];
for (UIView *v in viewsToCheck)
{
if ([v isKindOfClass:[CharacterTile class]])
{
if (CGRectContainsPoint(v.frame, nowPoint))
{
CharacterTile *ctTemp = (CharacterTile *)v;
//perform your work with the subview.
}
}
}
}
where CharacterTile are the subviews added on self.view.
CGRectContainsPoint tells if the point touched by user is inside a view or not.
I have the following problem.
I am using a UILongPressGestureRecognizer to put a UIView into a "toggle mode". If the UIView is in "toggle mode" the user is able to drag the UIView around the screen. For dragging the UIView around the screen I am using the methods touchesBegan, touchesMoved and touchesEnded.
It works, but: I have to lift my finger in order to drag it, because the touchesBegan method got already called and therefore is not called again and therefore I can't drag the UIView around the screen.
Is there any way to manually call touchesBegan after UILongPressGestureRecognizer got triggered (UILongPressGestureRecognizer changes a BOOL value and the touchesBegan only works if this BOOL is set to YES).
UILongPressGestureRecognizer is a continuous gesture recognizer, so rather than resorting to touchesMoved or UIPanGestureRecognizer, just check for UIGestureRecognizerStateChanged, e.g.:
- (void)viewDidLoad
{
[super viewDidLoad];
UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
[self.view addGestureRecognizer:gesture];
}
- (void)handleGesture:(UILongPressGestureRecognizer *)gesture
{
CGPoint location = [gesture locationInView:gesture.view];
if (gesture.state == UIGestureRecognizerStateBegan)
{
// user held down their finger on the screen
// gesture started, entering the "toggle mode"
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
// user did not lift finger, but now proceeded to move finger
// do here whatever you wanted to do in the touchesMoved
}
else if (gesture.state == UIGestureRecognizerStateEnded)
{
// user lifted their finger
// all done, leaving the "toggle mode"
}
}
I would suggest you to use UIPanGestureRecognizer as it a recommended gesture for dragging.
You can configure the min. and max. number of touches required for a panning, using the following the properties:
maximumNumberOfTouches
minimumNumberOfTouches
You can handle the states like Began, Changed and Ended, like having animation for the required states.
Using the below method translate the point to the UIView in which you want it.
- (void)setTranslation:(CGPoint)translation inView:(UIView *)view
example:
You have to use a global variable to retain the old frame. Get this in UIGestureRecognizerStateBegan.
When the state is UIGestureRecognizerStateChanged. You can use the
-(void) pannningMyView:(UIPanGestureRecognizer*) panGesture{
if(panGesture.state==UIGestureRecognizerStateBegan){
//retain the original state
}else if(panGesture.state==UIGestureRecognizerStateChanged){
CGPoint translatedPoint=[panGesture translationInView:self.view];
//here you manage to get your new drag points.
}
}
Velocity of the drag. Based on the velocity you can provide a animation to show bouncing of a UIView
- (CGPoint)velocityInView:(UIView *)view
Just like the title ,when I touch the UIView I want the touch point to be glow, I came up with a idea that to show a glow image on the touch point ,but if by code?any example or idea?thanks for sharing!!
You can try touchesBegan event below Code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if([touch view] ==self.my_view)//Check click your uiview or not
{
CGRect frame = [your_image_view frame];
CGPoint touchLocation = [touch locationInView:touch.view];
frame.origin.x=touchLocation.x;
frame.origin.y=touchLocation.y;
[your_image_view setFrame:frame];
[self.my_view addSubview:your_image_view];
}
}
Thanks..!
Well the first step would be to detect the touch on your UIView for that I would recommend using the high level API UIGestureRecognizer andd add to your view. Then you can use the call back to do whatever you want, perhaps some sort of animation?. If so you can use an animation block to animate your changes.