I'm trying to make a quiz game. I turn the xib view into Image View to place one of my pre-made question images. After I placed the image I choose a button and place it on the image. However, the button completely supersedes the image. Even after I set the button type to custom, I can't see the image. The idea is just to place four invisible buttons and according to the answer proceed to the next question or display the wrong answer image. Thanks for any help.
Why not use a tap gesture recognizer?
Option 1
Step 1: Add tapGestureRecognizer to image views
for (UIImageView * v in #[v1, v2, v3, v4]) {
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleTap:)];
tap.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tap];
}
Step 2: Recieve Taps
- (void) handleTap:(UITapGestureRecognizer *)tap {
if (tap.view == v1) {
NSLog(#"V1 was tapped");
}
else if (tap.view == v2) {
NSLog(#"V2 was tapped");
}
else if (tap.view == v3) {
NSLog(#"V3 was tapped");
}
else if (tap.view == v4) {
NSLog(#"V4 was tapped");
}
}
Option 2 - Michael Knudsen's Answer
Here is the alternative method suggested by Michael
Step 1: Add tapGestureRecognizer to image views
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleTap:)];
tap.numberOfTapsRequired = 1;
[imageViewsParentView addGestureRecognizer:tap];
Step 2: Recieve Taps
- (void) handleTap:(UITapGestureRecognizer *)tap {
CGPoint positionInView = [tap locationInView:tap.view];
if (CGRectContainsPoint(v1.frame, positionInView)) {
NSLog(#"V1 was tapped");
}
else if (CGRectContainsPoint(v2.frame, positionInView)) {
NSLog(#"V2 was tapped");
}
else if (CGRectContainsPoint(v3.frame, positionInView)) {
NSLog(#"V3 was tapped");
}
else if (CGRectContainsPoint(v4.frame, positionInView)) {
NSLog(#"V4 was tapped");
}
}
You may be able to solve it by somehow making your view transparent. However, I would suggest another solution: Add a UITapGestureRecognizer and, whenever it senses a tap, check if its coordinates are inside one of the desired areas (corresponding to your imaginary buttons).
You can use touchesBegan method to detect which image was tapped.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if([touch view] == answerImg1) //answerImg1 as your first image
{
// Do whatever you want when first image tapped
}
else if([touch view] == answerImg2)
{
// Do whatever you want when second image tapped
}
else if([touch view] == answerImg3)
{
// Do whatever you want when third image tapped
}
else
{
NSLog(#"Other view tapped");
}
}
Related
I am using a UICollectionView in my ViewController for displaying images and i want that user should be able to delete photos on long press, but i am not able to detect long press gesture. I have read all the previous discussions and tried to implement them in my project also but none of them worked for me.
Enable user interaction for your imageview by below line
imgview.userInteractionEnabled =YES;
//Here is sample code
UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc] init];
[gestureRecognizer addTarget:self action:#selector(imgLongPressed:)];
gestureRecognizer.delegate = self;
imgview.userInteractionEnabled =YES;
[imgview addGestureRecognizer: gestureRecognizer];
- (void) imgLongPressed:(UILongPressGestureRecognizer*)sender
{
UIImageView *view_ =(UIImageView*) sender.view;
CGPoint point = [sender locationInView:view_.superview];
if (sender.state == UIGestureRecognizerStateBegan)
{
}
else if (sender.state == UIGestureRecognizerStateChanged)
{
}
else if (sender.state == UIGestureRecognizerStateEnded)
{
}
}
I am using UITapGestureRecognizer for detecting which UIView was tapped on my screen but for some reason it only detects the parent view tap, for example below code logs only parent views tag. How do i detect subview taps which are present on main view. Please suggest.
Inside View did load :-
UITapGestureRecognizer *viewTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(actionForViewTapped:)];
[self.view addGestureRecognizer:viewTapRecognizer];
Method outside view did load.
-(void) actionForViewTapped:(UITapGestureRecognizer*)sender {
NSLog(#"view tapped");
UIView *view = sender.view;
NSLog(#"view tag is %lu", view.tag); //Always prints parent view tag.
if(view.tag == 10){
NSLog(#"tag1 tapped"); //Not called
}
if(view.tag == 20){
NSLog(#"tag 2 tapped"); //Not called
}
}
We have more options to find detecting on sub view by tap gesture
CHOICE 1:Directly tap to SubView
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tapSubView)];
tapGesture.numberOfTapsRequired = 1;
[subView addGestureRecognizer:tapGesture];
CHOICE 2:Finding tap on SubView through Parent View
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tapSubView)];
tapGesture.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapGesture];
-(void)tapSubView:(UITapGestureRecognizer *)sender
{
UIView* view = sender.view;
CGPoint loc = [sender locationInView:view];
UIView* subview = [view hitTest:loc withEvent:nil];
//OR
CGPoint point = [sender locationInView:sender.view];
UIView *viewTouched = [sender.view hitTest:point withEvent:nil];
if ([viewTouched isKindOfClass:[self.view class]])
{
NSLog(#"the subView is called");
}
else
{
NSLog(#"the subView is not called");
}
}
Printed Output is
the subView is called
CHOICE 3:Find Tap Detection using Delegate methods of Gesture
First You have to add the GestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if([touch.view isKindOfClass: [self.view class]] == YES)
{
return YES; // return YES (the default) to allow the gesture recognizer to examine the touch object
}
else {
return NO; //NO to prevent the gesture recognizer from seeing this touch object.
}
}
The gesture recognizer is only associated with one specific view, which means it will only recognize touches on the view it is added to. If you want to know which subview was touched, then you will need to do a couple of things:
Set userInteractionEnabled = false for each subview. This will make it so that every touch on a subview is passed up to the parent view, and the touch will be recognized by the gesture recognizer.
There isn't enough information on your view hierarchy or layout to know exactly how to proceed from here, but you can use one or some of these methods to determine which view was touched: UIView.hitTest(_:with:), UIView.point(inside:with:), CGRectContainsPoint() or UIGestureRecognizer.location(in:). For example, if the subviews do not overlap each other, you could use the following code snippet to test if the touch was in a particular view:
let location = tapGesture.locationInView(parentView)
if CGRectContainsPoint(subview1, location) {
// subview1 was touched
}
i am creating drawer
self.isShowMenuVC = NO;
_menuView = [MenuViewController viewController];
[self.menuView setDelegate:self];
[self addChildViewController:self.menuView];
[self.menuView.view setFrame:CGRectMake(-kMenuTableWidth, 0, kMenuTableWidth, self.view.frame.size.height)];
[self.view addSubview:self.menuView.view];
[self.menuView didMoveToParentViewController:self];
UITapGestureRecognizer *outsideTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(outsideTapped:)];
[self.view addGestureRecognizer:outsideTap];
outsideTap.delegate = self;
and when button tap i just set frame of _menuView.view to behave like a drawer
what i want is to detect touch outside of drawer but i am not able to do it
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (touch.view == self.menuView.view) {
NSLog(#"Touch Drawer");
} else {
NSLog(#"Touch Outside");
}
return YES;
}
but it is always show Touch Outside"
i am missing something but don't know what thanks in advance
Also try with 2 gesture but not working because one gesture in self.view so, when i tap in drawer method call 2 times.
for that i tried to disable one gesture, still calling two times
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (gestureRecognizer == self.touchInDrawer) {
NSLog(#"Touch in drawer");
[self.touchOutSideDrawer setEnabled:NO];
} else {
NSLog(#"Outside");
[self hideMenuView];
}
return YES;
}
The UITapGestureRecognizer cannot detect the touch outside the view which it belongs to.
You need to create another UITapGestureRecognizer and add them to self.menuView.view.
Also you can make two #property for your gesture recognizers and check them inside method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (gestureRecognizer == self.firstGesture) {
NSLog(#"Touch in first gesture");
} else {
NSLog(#"Touch in another gesture");
}
I have solve this issue with adding two gesture
#property (strong,nonatomic) UITapGestureRecognizer *touchInDrawer;
#property (strong,nonatomic) UITapGestureRecognizer *touchOutSideDrawer;
as per #Eugene Zaychenko's Answer but there is still problem because delegate method calling two times
also i can't [self.touchOutSideDrawer setEnabled:NO]; when touch in drawer tapped, because after that it will remove from the view and never executed again if [self.touchOutSideDrawer setEnabled:YES];
but most interesting thing is
_touchInDrawer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(outsideTapped:)];
[self.menuView.view addGestureRecognizer:self.touchInDrawer];
self.touchInDrawer.delegate = self;
_touchOutSideDrawer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(outsideTapped:)];
[self.view addGestureRecognizer:self.touchOutSideDrawer];
self.touchOutSideDrawer.delegate = self;
outsideTapped method calling only one time so i shifted my all code there and is working
- (void) outsideTapped:(UITapGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer == self.touchOutSideDrawer) {
// [self.view removeGestureRecognizer:self.touchOutSideDrawer];
[self hideMenuView];
NSLog(#"Outside");
} else {
NSLog(#"Touch in drawer");
// [self.touchOutSideDrawer setEnabled:NO];
}
}
Hi I have some buttons that trigger action methods.
In addition, I would like the user to be able to swipe left or right over the area with the buttons to show some different buttons
My idea was to add a UIView with a clear background color on top of the buttons so that the user could still see the buttons but could also swipe to the right or left.
However, when the view is over the buttons the buttons no longer work and when it is under the buttons, the swipe is not detected.
In addition to changing the view color to clear, I also tried adjusting the alpha however this seems to work the same way. When alpha of the UIView is zero, swipes are no longer detected and when alpha is greater than zero, the buttons no longer work.
Can anyone suggest a way to do this?
Thanks in advance for any suggestions.
Code I am using for buttons and to detect swipes seems standard. Trying to figure out a way to expose view and buttons at the same time.
Action methods to which buttons are wired:
//.h file
- (IBAction)showIncoming:(id)sender;
- (IBAction)showOutcoming:(id)sender;
/.m file
- (IBAction)showIncoming:(id)sender {
_showIncoming=YES;
_fetchedResultsController=nil;
[self.tableView reloadData];
[self updateInterface];
}
- (IBAction)showOutgoing:(id)sender {
_showIncoming=NO;
_fetchedResultsController=nil;
[self.tableView reloadData];
[self updateInterface];
}
Swipes:
//in viewWillAppear
UISwipeGestureRecognizer *rightRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(rightSwipeHandle:)];
rightRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[rightRecognizer setNumberOfTouchesRequired:1];
rightRecognizer.delegate = self;
[_topView addGestureRecognizer:rightRecognizer];
[_topView setUserInteractionEnabled:YES];
// [rightRecognizer release];
//........towards left Gesture recogniser for swiping.....//
UISwipeGestureRecognizer *leftRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(leftSwipeHandle:)];
leftRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
[leftRecognizer setNumberOfTouchesRequired:1];
leftRecognizer.delegate = self;
[_topView addGestureRecognizer:leftRecognizer];
[_topView setUserInteractionEnabled:YES];
}
- (void)rightSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
//Do moving
NSLog(#"Right Swipe performed");
_showOld=YES;
[self updateInterface];
}
- (void)leftSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
// do moving
NSLog(#"Left Swipe performed");
_showOld=NO;
[self updateInterface];
}
The approach I suggest is listening to a user moving a finger events and firing specified method that would check if user's finger is on your button's view. Sample code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchedViewWithTouches:touches andEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchedViewWithTouches:touches andEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchedViewWithTouches:touches andEvent:event];
}
- (void)didTouchedButton:(NSSet *)touches andEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:touch.view];
UIView *touchedView;
for (UIView *view in self.subviews) {
if(CGRectContainsPoint(view.frame, touchLocation)) {
touchedView = view;
break;
}
}
if (view == self.showIncomingButton) {
[self showIncoming:self.showIncomingButton];
} else if (view == self.showOutcomingButton) {
[self howOutcoming:self.showOutcomingButton];
}
}
Note that you will have to add two outlets for your buttons (if you don't have any). Also, you can get rid off (id)sender in your IBAction calls.
I'm trying to make a vertical line from the top of my main view to the bottom, and it will trigger an action when someone swipes and crosses this line from either direction. I've already tried creating a tall thin label and putting a swipe recognizer inside of this, but it does not work the way I want. It only detects a swipe when you start inside of the label and swipe but not if you start outside the label and cross through it.
Here is my code so far,
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(doSomething)];
swipe.direction = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight;
swipe.numberOfTouchesRequired = 1;
[self.myLabel setUserInteractionEnabled:YES];
[self.myLabel addGestureRecognizer:swipe];
The easiest way is to use the touchesBegan: and touchesMoved: method on a UIView to decide if it's crossed the midway line. You would then just add a view (your line) on top of this view, and you may want to disable user interaction on your "line" view. BTW, a quick dirty way to create a line is to create a view that's 2px wide (or whatever width you want) and set it's background color to your "line" color...
You need to decide in touchesBegan: which side they started on, and then do something like this in touchesMoved::
- (void) touchesMoved: (NSSet *)touches withEvent:(UIEvent *)event {
CGPoint tappedPt = [[touches anyObject] locationInView: self];
if (tappedPt.x > self.frame.width/2 && self.userStartedOnLeftSide)
// User crossed the line...
else if (tappedPt.x < self.frame.width/2 && !self.userStartedOnLeftSide)
// User crossed the line...
else
// You probably don't need this else, the user DID NOT cross the line...
}
Similarly, you could do this in a UIViewController with a swipe gesture recognizer something like this:
- (void)swipe:(UISwipeGestureRecognizer *)recognizer{
CGPoint point = [recognizer locationInView:[recognizer view]];
if (recognizer.state == UIGestureRecognizerStateBegan)
// The user began their swipe at point
else if (recognizer.state == UIGestureRecognizerStateEnded)
// The user ended their swipe at point
// Add some logic to decide if they crossed the line...
}
If you're just trying to detect left and right swipes, you can put it on your main view like so:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UISwipeGestureRecognizer *swipe;
swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
swipe.direction = UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:swipe];
swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
swipe.direction = UISwipeGestureRecognizerDirectionRight;
[self.view addGestureRecognizer:swipe];
}
- (void)handleSwipe:(UISwipeGestureRecognizer *)gesture
{
NSLog(#"%d", [gesture numberOfTouches]);
if (gesture.direction == UISwipeGestureRecognizerDirectionLeft)
{
NSLog(#"LEFT");
}
if (gesture.direction == UISwipeGestureRecognizerDirectionRight)
{
NSLog(#"RIGHT");
}
}
If you wanted to really test to see if you crossed the midpoint, you could use aUIPanGestureRecognizer:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.view addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)]];
}
- (void)handlePan:(UIPanGestureRecognizer *)gesture
{
static CGPoint startLocation;
static BOOL startAtLeft;
CGPoint location = [gesture locationInView:gesture.view];
if (gesture.state == UIGestureRecognizerStateBegan)
{
startLocation = location;
startAtLeft = (location.x < (gesture.view.frame.size.width / 2.0));
}
else if (gesture.state == UIGestureRecognizerStateEnded)
{
BOOL nowAtLeft = (location.x < (gesture.view.frame.size.width / 2.0));
if (startAtLeft != nowAtLeft)
{
if (startAtLeft)
NSLog(#"swiped across midpoint, left to right");
else
NSLog(#"swiped across midpoint, right to left");
}
}
}
With the pan gesture, you can customize this to your heart's content (e.g. recognize gesture as soon as the user's finger crosses rather than waiting for them to end the gesture, etc.).