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.
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 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.
I'm using Xcode to develop an app for iOS where the user can rate some content by touching the corresponding smiley icon (from frown to big smile). At the moment, each smiley icon behaves as a single button: when one of the smileys is touched, its color changes to show the user his/her choice.
However, being the icons small in the iPhone display, it is not easy to touch with precision the desidered smiley, and the user is likely to make errors.
I would like improve my rating system to mimic the behavior of the IOS keyboard for iPhone when it shows on top of the finger the selected character, and inputs the character just when the user releases the finger.
More precisely, I would like my 5 smiley items to behave not as separated buttons, but as a slider with 5 discrete points: when the user's finger is held on an item (covering it), a zoomed version on top appears, the user can continue sliding and when he/she releases the finger the selected item is chosen. I created a small animation to show what I would like to achieve:
Which method or class would you recommend to use to achieve this effect?
You don't need to go for popover controller. Here is what you can do.
Implement this method in your ViewController:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
for (UIImageView *sView in self.smileyImages)
//smileyImages is outletCollection of smileyImageViews.
{
if (CGRectContainsPoint([sView frame], point))
{
[self.popupView setHidden:NO];
//popupView is the popup view you want to show.
[self.popupImage setImage:[sView image]];
//popupImage is enlarged image of smiley in popup view you want to show.
CGPoint newCenter= CGPointMake(sView.center.x, sView.center.y-40);
//This fixes position of your popupView.
[self.popupView setCenter:newCenter];
}
}
}
Here is the Github of the code. I've just implemented popup for you. Rest you can do I think. If not, Let me know.
Update:
Add this method for desired results
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
for (UIImageView *sView in self.smileyImages)
{
if (CGRectContainsPoint([sView frame], point))
{
self.selectedImage= sView.image;
[self.popupView setHidden:YES];
break;
}
}
}
Update2:
Previous update has some issues, go for this code instead:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
self.selectedImage= self.popupImage.image;
[self.popupView setHidden:YES];
}
I'm working on an iOS app.
I have a UIView that is being animated. It keeps moving from left to right.
This view has several UIView children. They move within their parent when this is being animated.
When I try to capture user touches on the children (by using a UITapGestureRecognizer), it doens't work as expected. It sort of detect some touches on the children, but not in the position where they currently are.
I've been struggling with this for a while now. Any ideas about how to solve this? I really need to detect which children the user is touching.
Thanks!
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self];
// Check every child subview
for (UIView *tickerItem in self.subviews)
{
// Check collision
if ([tickerItem.layer.presentationLayer hitTest:touchLocation])
{
MKTickerItemView *v = (MKTickerItemView*)tickerItem;
NSLog(#"Selected: %#", v.title);
// This button was hit whilst moving - do something with it here
break;
}
}
}
There is a UIViewAnimationOptions value...
UIViewAnimationOptionAllowUserInteraction
You can use this in the [UIView animateWithDuration... code.
This will enable the touch.
Objective: To get one image at a time to glow, as finger is dragged over each of a series of images.
In an attempt to figure this out on my own, I tried to update the Alpha of the touched image to 1.00 while setting all others in the series of images to alpha 0.25 as finger drags over each individual image via touchesMoved? However my methods below did not produce the desired result.
Artwork for Glow overlay for each of the eight images is created in viewDidLoad using this pattern:
-(void)viewDidLoad
{
Glow *imageOne = [[Glow alloc]
initWithNibName:#"ImageOne" bundle:[NSBundle mainBundle]];
self.glowOneView = imageOne;
[imageOne release];
[self.glowOneView setTag:101];
[self.glowOneView setAlpha:0.25];
[self.glowOneView setCenter:CGPointMake(160,135)];
[self.view insertSubview:self.glowOneView atIndex:11];
}
(repeating the above pattern to uniquely create each of the remaining eight images).
touchesMoved pattern looks like this:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches Began");
UITouch *touch = [touches anyObject];
if ([touch view] == glowOneView) {
[glowOneView setAlpha:1.00];
[glowTwoView setAlpha:0.25];
[glowThreeView setAlpha:0.25];
[glowFourView setAlpha:0.25];
[glowFiveView setAlpha:0.25];
[glowSixView setAlpha:0.25];
[glowSevenView setAlpha:0.25];
[glowEightView setAlpha:0.25];
NSLog(#"Began Button One");
}
else if ([touch view] == glowTwoView) {
[glowOneView setAlpha:0.25];
[glowTwoView setAlpha:1.00];
[glowThreeView setAlpha:0.25];
[glowFourView setAlpha:0.25];
[glowFiveView setAlpha:0.25];
[glowSixView setAlpha:0.25];
[glowSevenView setAlpha:0.25];
[glowEightView setAlpha:0.25];
NSLog(#"Began Button Two");
}
...
(repeating the above pattern to uniquely handle each of the remaining eight images).
The code snippets above will glow the first image touched, but as you drag around the view touchesMoved won't update the alpha for any subsequent image the finger is dragged over, until the touch is released and a new touch is initiated.
The Console shows the touchesMoved NSLog from the first image touched only, and continually repeats the NSLog for that first image touched for as long as the finger is dragged, no matter which image is subsequently under the dragging finger.
I would really appreciate your advice and any example that replaces or updates the above methods to produce the desired result of getting one image at a time to glow, as a finger is dragged over each of a series of images.
Thank you,
I've implemented something similar to what you describe. Assuming this code is in the view that contains your Glow views, you need to do a couple of things: 1) have your container view intercept touch events by returning itself from hitTest:withEvent:, and 2) in touchesMoved:withEvent:, call UIView's implementation of hitTest:withEvent: to figure out which view the touch is in.
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
// intercept all touches inside container
if ([self pointInside:point withEvent:event]) {
return self;
}
return nil;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
// figure out which view the touch is in
UIView *view = [super hitTest:[[touches anyObject] locationInView:self] withEvent:nil];
// highlight Glow subview under touch
if ([view isKindOfClass:[Glow class]]) {
[view setAlpha:1.0];
}
// un-highlight all other Glow subviews
for (UIView *subview in [self subviews]) {
if (subview != view && [subview isKindOfClass:[Glow class]]) {
[subview setAlpha:0.25];
}
}
}
You'll probably want to also implement touchesBegan:withEvent: to highlight the view before the touch starts moving and touchesCancelled:withEvent: and touchesEnded:withEvent: to un-highlight all.