Why do my touch event not work? - objective-c

I have declared a void touchesbegan method in my controller but it doesn't work! i don't know why. i have an image view which i plan to click it to move to next controller. so i set the touches began method. i have linked the image view in the xib file but when i click the image. nothing happens. Please help, Thanks.
ViewController.h
#import <UIKit/UIKit.h>
#interface imageViewViewController : UIViewController
{
IBOutlet UIImageView *testing;
}
#property(nonatomic, retain) IBOutlet UIImageView *testing;
#end
ViewController.m
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if(touch.view == testing)
{
TestViewController *testviewcontroller = [[TestViewController alloc]initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:testviewcontroller animated:YES];
}
}
#end
P.S.
here i tried another method using tap gestures.
testing is the name of my image view. as u can see i comment out the ns log in the imagedidtapped method. it works til that point. however when i tried to navigate it out to another page it fails.
- (void)viewDidLoad
{
UITapGestureRecognizer *tapRecognizer;
[testing setTag:0];
[testing setUserInteractionEnabled:TRUE];
tapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageViewDidTapped:)] autorelease];
tapRecognizer.numberOfTapsRequired = 1;
[testing addGestureRecognizer:tapRecognizer];
[self.view addSubview:testing];
[testing release];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)imageViewDidTapped:(UIGestureRecognizer *)aGesture {
UITapGestureRecognizer *tapGesture = (UITapGestureRecognizer *)aGesture;
UIImageView *tappedImageView = (UIImageView *)[tapGesture view];
switch (tappedImageView.tag) {
case 0:
//NSLog(#"UIImageView 1 was tapped");
[self navigate];
break;
case 1:
NSLog(#"UIImageView 2 was tapped");
break;
default:
break;
}
}
-(void)navigate
{
TestViewController *testviewcontroller = [[TestViewController alloc]initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:testviewcontroller animated:YES];
}

The problem is that by default userInteractionEnabled is NO for a UIImageView so you won't get any touches. Set it to YES.
Also the message handling for touchesBegan is really complicated. You'll be much happier if you attach a UITapGestureRecognizer to the image view.
EDIT: Now you say your touches handling is working, but the navigation is not taking place. So let's concentrate on this part of your code:
-(void)navigate
{
TestViewController *testviewcontroller = [[TestViewController alloc]initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:testviewcontroller animated:YES];
}
Put logging in there to make sure navigate is being called! If it isn't being called, you need to figure out why your other code is not running and calling it. If it is being called, then the problem is probably that self.navigationController is nil, i.e. you are not inside a navigation interface to start with.

Related

iOS 7: Custom container view controller with UINavigationController as a child view controller

I would like to write a custom full-screen container view controller with the intention of putting a UINavigationController in it as a child view controller. The view of the UINavigationController will fill up the view of the container view controller so that it looks like the UINavigationController is the root view controller. (One would want to do something like this to, say, create the sliding sidebar menu UI popularized by Facebook.)
What I've done works EXCEPT there is a glitch when presenting another view controller that hides the status bar when the iPhone is in landscape orientation. Typically, the navigation bar slides up when the status bar disappears and slides down when it reappears. Instead, the navigation bar stays where it is when it is suppose to slide up, and when it is suppose to slide down, it is first positioned with the status bar overlapping it and then jumps to its correct position below the status bar. Basically, I'm trying to have the UINavigationController behave as it would if it were not inside a custom container view controller.
Below is some code that you can run to see the problem, but if you don't want to do that, just take a look at the ContainerViewController class, which implements a minimal custom container view controller. What is it that I'm missing in my custom container view controller that is causing this problem? It works when I use a UITabBarController as the container view controller, so it seems like I'm just missing something in my implementation.
MORE STUFF BELOW TO READ IF YOU WANT
If you would like to run the sample code to see the problem, here is an overview. There is a preprocessor definition called MODE defined in AppDelegate to conditionally compile the app in three ways.
When MODE == 1, ViewController is inside a UINavigationController. You can then press a "Present" button to present ViewControllerWithStatusBarHidden, and then you can press a "Dismiss" button to dismiss this view controller. This mode of the app shows the behavior that I am seeking.
When MODE == 2, we have the same thing as in MODE == 1 except that the UINavigationController is inside of a ContainerViewController. This mode of the app shows the undesirable behavior I have currently.
When MODE == 3, we have the same thing as in MODE == 1 except that the UINavigationController is inside of a UITabBarController. This mode of the app shows that it is possible to get the behavior I am seeking.
Again, to see the problem, just press the "Present" button and then the "Dismiss" button when the iPhone is in landscape orientation.
CODE
Four classes:
ContainerViewController
AppDelegate
ViewController
ViewControllerWithStatusBarHidden
ContainerViewController.h
#import <UIKit/UIKit.h>
#interface ContainerViewController : UIViewController
#property (nonatomic) UIViewController * viewController;
#end
ContainerViewController.m
#import "ContainerViewController.h"
// This custom container view controller only has one child view controller,
// whose view fills up the view of the container view controller.
#implementation ContainerViewController
- (UIViewController *)viewController {
if (self.childViewControllers.count > 0) {
return [self.childViewControllers firstObject];
}
else {
return nil;
}
}
- (void)setViewController:(UIViewController *)viewController {
UIViewController *previousViewController = [self.childViewControllers firstObject];
if ((previousViewController == nil && viewController != nil)
|| (previousViewController != nil && viewController == nil)
|| (previousViewController != nil && viewController != nil
&& previousViewController != viewController))
{
if (previousViewController != nil) {
// Remove the old child view controller.
[previousViewController willMoveToParentViewController:nil];
[previousViewController.view removeFromSuperview];
[previousViewController removeFromParentViewController];
}
if (viewController != nil) {
// Add the new child view controller.
[self addChildViewController:viewController];
self.viewController.view.frame = self.view.bounds;
self.viewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.viewController.view];
[self.viewController didMoveToParentViewController:self];
}
}
}
- (UIViewController *)childViewControllerForStatusBarHidden {
return self.viewController;
}
- (UIViewController *)childViewControllerForStatusBarStyle {
return self.viewController;
}
#end
AppDelegate.h
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.h"
#import "ContainerViewController.h"
#define MODE 2 // Mode can be 1, 2, or 3.
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *vc = [[ViewController alloc] initWithNibName:nil bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
#if MODE == 1 // No container view controller.
self.window.rootViewController = nav;
#elif MODE == 2 // Use custom container view controller.
ContainerViewController *container = [[ContainerViewController alloc] initWithNibName:nil bundle:nil];
container.viewController = nav;
self.window.rootViewController = container;
#elif MODE == 3 // Use tab bar controller as container view controller.
UITabBarController *tab = [[UITabBarController alloc] initWithNibName:nil bundle:nil];
tab.viewControllers = #[nav];
self.window.rootViewController = tab;
#endif
[self.window makeKeyAndVisible];
return YES;
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
ViewController.m
#import "ViewController.h"
#import "ViewControllerWithStatusBarHidden.h"
// This view controller will serve as the content of a navigation controller.
// It also provides a button in the navigation bar to present another view controller.
#implementation ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = #"Title";
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Present"
style:UIBarButtonItemStylePlain
target:self
action:#selector(pressedPresentButton:)];
}
return self;
}
- (void)loadView {
self.view = [[UIView alloc] init];
self.view.backgroundColor = [UIColor whiteColor];
}
- (void)pressedPresentButton:(id)sender {
ViewControllerWithStatusBarHidden *vc = [[ViewControllerWithStatusBarHidden alloc] initWithNibName:nil bundle:nil];
[self presentViewController:vc animated:YES completion:nil];
}
#end
ViewControllerWithStatusBarHidden.h
#import <UIKit/UIKit.h>
#interface ViewControllerWithStatusBarHidden : UIViewController
#end
ViewControllerWithStatusBarHidden.m
#import "ViewControllerWithStatusBarHidden.h"
// This view controller is meant to be presented and does two things:
// (1) shows a button to dismiss itself and (2) hides the status bar.
#implementation ViewControllerWithStatusBarHidden
- (void)loadView {
self.view = [[UIView alloc] init];
self.view.backgroundColor = [UIColor yellowColor];
}
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *dismissButton = [UIButton buttonWithType:UIButtonTypeSystem];
[dismissButton setTitle:#"Dismiss" forState:UIControlStateNormal];
[dismissButton addTarget:self
action:#selector(pressedDismissButton:)
forControlEvents:UIControlEventTouchUpInside];
dismissButton.frame = CGRectMake(100, 100, 100, 100);
[self.view addSubview:dismissButton];
}
- (void)pressedDismissButton:(id)sender {
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
- (BOOL)prefersStatusBarHidden {
return YES;
}
//- (NSUInteger)supportedInterfaceOrientations {
// return UIInterfaceOrientationMaskPortrait;
//}
#end

How to assign UIImageView delegate to its super UIView so that it can know which UIImageView is touched

I have several UIImageViews contained by a UIView. My idea is when a UIImageView is touched, the UIView can know which one is touched thru delegate.
Here's my code
MyImageView.h
#protocol MyImageViewDelegate
-(void)toucheDelegate:(id)sender;
#end
#interface MyImageView:UIImageView{
id<MyImageViewDelegate> delegate;
}
#property(assign) id<MyImageViewDelegate> delegate;
#end
MyImageView.h
#implementation MyImageView
#synthesize delegate
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.delegate touchDelegate:self];
}
MyView.m
-(void)functionA{
for(int i=0;i<4;i++){
MyImageView *imageView=[[MyImageView alloc] init];
imageView.delegate=self; //Here it gives a warning saying Assigning to 'id<MyImageViewDelegate>' from incompatible type 'MyView *'
[self addSubview:imageView];
[imageView release];
}
}
-(void)touchDelegate:(id)sender{
NSLog(#"in superview");
}
The exception is unrecognized seletor sent to instance 0x7526c30. What does this mean?
I'm new to objective c and I'm not very clear about this delegate thing or the warning I mentioned in the code block. What's the problem? Any suggestion?
You Can Implement in this way
Create and Image then enable userInteraction by [imageView setUserInteractionEnabled:YES] Then add tag and Give UITapGestureRecognizer with a selector that's all you need to doo.
for(int i=0;i<4;i++){
MyImageView *imageView=[[MyImageView alloc] init];
[imageView setUserInteractionEnabled:YES];
[self.view addSubview:imageView];
[self.imageView setUserInteractionEnabled:YES];
[self.imageView setImage:[UIImage imageNamed:#"delete.png"]];
[self.imageView setTag:i];
UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imgTouchUp:)];
tapped.numberOfTapsRequired = 1;
[self.imageView addGestureRecognizer:tapped];
}
Then In selector recognize UIImaged taped by their respective Tags which can be found as shown bellow.
-(void) imgTouchUp:(id)sender {
UITapGestureRecognizer *gesture = (UITapGestureRecognizer *) sender;
NSLog(#"Taped Image tag is %d", gesture.view.tag);
}
You can Also find various Gestures.
UITapGestureRecognizer.
UIPinchGestureRecognizer.
UIRotationGestureRecognizer.
UISwipeGestureRecognizer.
UIPanGestureRecognizer.
UILongPressGestureRecognizer.

dismissing the keyboard from a UITextField,UITextView as a subview of UIScrollView?

I have an application with UIScrollView added as a subview of UIView. i have added UITextField,UITextview as a subView of UIScrollView .I want to dismiss the keyboard when i tap in the scroll view. how can i do this?
Just add UITapGestureRecognizer
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[scr addGestureRecognizer:singleTap];
}
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
//Get touch point
CGPoint touchPoint=[gesture locationInView:scr];
//Hide keyBoard
[self.view endEditing:YES];
}
In iOS 7, you can achieve this easily.
scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
Try this,
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
tapGesture.cancelsTouchesInView = NO;
[scrollView addGestureRecognizer:tapGesture];
[tapGesture release];
}
-(void)dismissKeyboard
{
[txtNotes resignFirstResponder];
[textView resignFirstResponder];
}
When I added the gesture to a subclass of UIScrollView, I was having problems with the various gestures in my view tree interfering with each other, such as being able to click on subviews, scroll the view, and have the keyboard dismiss in all cases. I came up with this solution, which can be setup from a superclass of UIScrollView or from a UIViewController.
The DismissKeyboardTapGesture class uses ARC, works with any text fields under the view, and doesn't take over any clicks from subviews like buttons. Also takes advantage of iOS7 scrolling effect to dismiss keyboard.
Setting up from UISScrollView superclass:
_dismissKeyboard = [[DismissKeyboardTapGesture alloc] initWithView:self];
or from UIViewController:
_dismissKeyboard = [[DismissKeyboardTapGesture alloc] initWithView:self.view];
Here is the class:
#interface DismissKeyboardTapGesture : NSObject <UIGestureRecognizerDelegate>
#end
#implementation DismissKeyboardTapGesture
- (id)initWithView:(UIView *)view
{
self = [super init];
if (self) {
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTap:)];
singleTap.cancelsTouchesInView = NO;
singleTap.delegate = self;
[view addGestureRecognizer:singleTap];
if ([view respondsToSelector:#selector(setKeyboardDismissMode:)]) {
// Bonus effect to dismiss keyboard by scrolling
((UIScrollView *)view).keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
}
}
return self;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
// Don't stop any existing gestures in our view from working
if (otherGestureRecognizer.view == gestureRecognizer.view) {
return YES;
}
return NO;
}
- (void)singleTap:(UIGestureRecognizer*)gestureRecognizer
{
// Close keyboard for any text edit views that are children of the main view
[gestureRecognizer.view endEditing:YES];
}
#end

initWithFrame is filling the screen instead of creating a frame of the size I want

I'm new to Cocoa development and suspect that this is a noob issue.
I'm creating a simple background canvas with a bespoke UIView. I was expecting that I would be able to create this canvas to be slightly indented down from the main view so that I could add a toolbar at a later date. However, when I use initWithFrame (and any other init for that matter), the canvas is always created to be the size of the full screen rather than slightly smaller than the full screen. Even if I completely override the values for CGRect it doesn't make a difference. I've set a touchesBegan event and set the background colour to green to be able to determine success but all I get are a completely green screen and a touch event that works everywhere.
Please help - this is driving me mad and I can't find the answer anywhere on the web.
The relevant code is as follows (there actually isn't much more code than this in the whole app so far):
AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.objMainViewController = [[MainViewController alloc] init];
self.window.rootViewController = self.objMainViewController;
[self.window makeKeyAndVisible];
return YES;
}
MainViewController.h
#import <UIKit/UIKit.h>
#import "viewCanvas.h"
#interface MainViewController : UIViewController
#property (strong, nonatomic) viewCanvas *objViewCanvas;
-(id)init;
#end
MainViewController.m
#import "MainViewController.h"
#import "viewCanvas.h"
#implementation MainViewController
#synthesize objViewCanvas;
-(id)init
{
if (self = [super init]) {
CGRect frame = CGRectMake(100, 100, 100, 100);
objViewCanvas = [[viewCanvas alloc] initWithFrame:frame];
}
return self;
}
- (void)loadView {
self.view = objViewCanvas;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
viewCanvas.h
#import <UIKit/UIKit.h>
#import "viewCanvas.h"
#interface viewCanvas : UIView {
}
//Init
- (id) initWithFrame:(CGRect)frame;
//Events
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
#end
viewCanvas.m
#import "viewCanvas.h"
#implementation viewCanvas
//Standard inits
- (id) initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
[self setBackgroundColor:[UIColor greenColor]];
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Touches Began Canvas" message:#"Canvas Touches Began" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles: nil];
[alert show];
}
#end
I think by default the view of a view controller fills the whole screen, so you need to add a subview to that view that's your smaller viewCanvas object (BTW, you should conform to the naming rules and name your classes with capital letters, ViewCanvas). Try this in your MainViewController .m file:
-(id)init{
if (self = [super init]) {
CGRect frame = CGRectMake(100, 100, 100, 100);
objViewCanvas = [[ViewCanvas alloc] initWithFrame:frame];
self.contentView = [[UIView alloc] initWithFrame:CGRectMake(1, 1, 1, 1)]; //this frame doesn't matter
[self.contentView setBackgroundColor:[UIColor whiteColor]];
}
return self;
}
- (void)loadView {
self.view = self.contentView;
[self.view addSubview:objViewCanvas];
}

New to iPhone SDK: touchesBegan not called

I created a very very basic iPhone app with File/New Projet/View-Based application.
No NIB file there.
Here is my appDelegate
.h
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MyViewController *viewController;
}
.m
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
And here is my loadView method in my controller
- (void)loadView {
CGRect mainFrame = [[UIScreen mainScreen] applicationFrame];
UIView *contentView = [[UIView alloc] initWithFrame:mainFrame];
contentView.backgroundColor = [UIColor redColor];
self.view = contentView;
[contentView release];
}
Now, in order to catch the touchesBegan event, I created a new subclass of UIView:
.h
#interface TouchView : UIView {
}
.m
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touch detected");
}
and modified the second line in my loadView into this :
TouchView *contentView = [[UIView alloc] initWithFrame:mainFrame];
Why is touchesBegan never called?
If you change the loadView into this:
TouchView *contentView = [[TouchView alloc] initWithFrame:mainFrame];
You should have no problem catching the touches in TouchView. In your code, you didn't create a TouchView instance, you created a UIView instance.
Found the solution : touchesBegan gets called on the viewController, not on the view...