I cant seem to push this view controller and I must be doing something wrong. Code
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:#selector(pushToStart) forControlEvents:UIControlEventTouchUpInside];
}
- (void)pushToStart
{
ViewController *view = [[ViewController alloc]init];
[[self navigationController] pushViewController:view animated:YES];
}
What am I doing wrong?
Create a UINavigationController programatically, or do it using Interface Builder - There are 100's of tutorials online on how to do this. For example here
Related
I'm new to ObjC and I'm trying to create Button outside ViewController file (following MVC paradigm).
What I did:
.h
#interface MainMenu : UIButton
-(UIButton *)addButton;
#end
.m
#implementation MainMenu
-(UIButton *)addButton {
UIButton* button = [[UIButton alloc] initWithFrame:CGRectMake(50.0, 50.0, 200.0, 75.0)];
[button setBackgroundColor:[UIColor colorWithRed:1.0
green:1.0
blue:0.0
alpha:1.0]];
[button setTitle:#"TITLE"
forState:UIControlStateNormal];
return button;
}
#end
In ViewController I want to create button on the screen and make it respond to touch event. So
.m
#implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
MainMenu *menuButton = [[MainMenu alloc] init];
[menuButton addTarget:self
action:#selector(ButtonClick)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:menuButton];
}
-(void)ButtonClick {
NSLog(#"You clicked on button!!!");
}
#end
I can make it work by implementing all in ViewController.m file, but wish I could have then separated. This code above doesnt show me a button
Second thing: I tried to add addTarget:action:forControlEvents: method to MainMenu.m instead of ViewController.m and I couldnt make it work properly because I need to pass ViewController as a target and method ButtonClick from ViewController.m as a selector (I guess)
So I'm interesting how to make it right according to MVC?
Thanks!
They way you are doing is bit wrong, as you subclassing UIButton and then you have instance method addButton which returns a button, don't make sense. Either you can add Class level method or just subclass and add another init method to fulfill your requirements.
Better would be if you want to create a custom button and want to add target action also do something like this
#interface CustomButton : UIButton
- (instancetype)initWithTarget:(id)target andAction:(SEL)action;
#end
in .m file
#implementation CustomButton
- (instancetype)initWithTarget:(id)target andAction:(SEL)action {
self = [super initWithFrame::CGRectMake(50.0, 50.0, 200.0, 75.0)];
if (self) {
[self setBackgroundColor:[UIColor colorWithRed:1.0
green:1.0
blue:0.0
alpha:1.0]];
[self setTitle:#"TITLE"
forState:UIControlStateNormal];
[self addTarget:target
action:action
forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
#end
and you can just use it like this anywhere
[self.view addSubView:[CustomButton alloc] initWithTarget:self andAction:#selector(name)]];
You are almost there. Here is what you have done right:
1) Subclassed UIButton to MainMenu class. (I would typically call this MainMenuButton or something more specific)
2) Set up, created, and configured an instance of MainMenu in ViewController.
Here is what you did wrong:
1) Did not implement a custom init method
2) Tried to setFrame from within the subclass, this should be done from ViewController
3) You need to make modifications to self, which is the current instance of the subclass, not a new variable called button
The addButton method will never be called, since there is nothing to call it. When customizing a UIButton subclass you will want to do all of this in a custom init method. Try replacing your addButton method with this code:
#implementation MainMenu
-(id)init {
self = [super init];
if(self) {
[self setBackgroundColor:[UIColor colorWithRed:1.0
green:1.0
blue:0.0
alpha:1.0]];
[self setTitle:#"TITLE"
forState:UIControlStateNormal];
}
return self;
}
#end
Then in ViewController create an instance of your MainMenu subclass, set the frame, and configure as you did previously. This init method will be called when you call [[MainMenu alloc] init]; and will configure the subclass before returning it to ViewController.
#implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
MainMenu *menuButton = [[MainMenu alloc] init];
[menuButton setFrame:CGRectMake(50.0, 50.0, 200.0, 75.0)];
[menuButton addTarget:self
action:#selector(ButtonClick)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:menuButton];
}
-(void)ButtonClick {
NSLog(#"You clicked on button!!!");
}
#end
I have a view controller named ViewController.
ViewController displays a UIView that has a button on it, which allows me to advance to a second view controller - SecondViewController.
SecondViewController also has a button on it, which allows me to advance to a third view controller.
However, I am having trouble displaying ThirdViewController. When I tap the button in SecondViewController it throws an error:
Warning: Attempt to present ... on ... whose view is not in the window hierarchy!
I have been to a bunch of other sites and posts that address this issue, but cannot seem to find a working solution. I have implemented quite a few solutions, but none seem to work.
Here is my code:
- (void)secondaryView:(UIView *)secondaryView
{
UIView *theView = secondaryView;
UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.frame = [UIScreen mainScreen].bounds;
[viewController.view addSubview:theView];
viewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:viewController animated:YES completion:nil];
}
secondaryView is a UIView that I am constructing elsewhere in the application. I add it to the viewController then present the viewController.
Is there any way to dynamically create UIViewControllers, add a UIView to each one, and add them to the window hierarchy?
If you can use navigation in your ViewControllers, you can try the below code
In the place where you call the firstViewController,
-(void)callFirst
{
FirstViewController *first = [FirstViewController alloc] init];
UINavigationController *navigationController = [UINavigationController alloc] initWithRootViewController:first];
navigationController.modalPresentaionStyle = UIModalPresenationFormSheet;
[self presentModalViewController:navigationController animated:YES];
}
And in the FirstViewController button action ,you can write
-(void)callSec
{
SecondViewController *sec = [SecondViewController alloc] init];
[self.NavigationController pushViewController:sec animated:YES];
}
And in SecondViewController you can do the same
-(void)callThird
{
ThirdViewController *third = [ThirdViewController alloc] init];
[self.NavigationController pushViewController:third animated:YES];
}
Try this...And in these ViewControllers you can do whatever coding you want to meet the requirement like
-(void)viewDidLoad
{
UIView *newView = [[UIView alloc] initWithFrame:CGRectMake(20,20,400,400)];
newView.backGroundColor = [UIColor redColor];
[self.view addSubView:newView];
}
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
So, another EXC_BAD_ACCESS topic on StackOverflow, but as I'm new to Objective-C this is still a topic I don't really grasp yet. Even though I have done a lot of research about it already.
The issue is the following. I have a UIScrollView that I have overwritten using a Custom Class (named MultiSelectView). If the user taps this UIScrollView and then I want to open a view that allows him to select some data.
So I have declared a UITapGestureRecognizer that calls the openMultiSelect: method. But on the line [parent.navigationController pushViewController:view animated:YES]; I get a Program received signal: "EXC_BAD_ACCESS". error. Why o why?
- (id) initWithCoder:(NSCoder *) coder {
self = [super initWithCoder: coder];
if (self) {
// Add a Tap Gesture Recognizer to the Scrollview.
// If the user taps the view, it triggers the 'openMultiSelect' method.
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(openMultiSelect:)];
[singleTap setNumberOfTapsRequired:1];
[singleTap setNumberOfTouchesRequired:1];
[self addGestureRecognizer:singleTap];
}
return self;
}
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];
[view release];
}
So the parent that you see is a ViewController that contains the tab. Is there a better way to do this? Because for now I have thus a ViewController that contains Tabs. In its activateTab: method I thus create the tab and pass self along. I do the same in the viewDidLoad for that tab to pass the parent to the custom UIScrollView:
- (void) activateTab:(int)index {
... code ...
self.tab_Basic = [[TabBasic alloc] initWithNibName:#"TabBasic" bundle: [NSBundle mainBundle]];
self.tab_Basic.parent = self;
... code ...
}
You should make some change to your callback method. Something like that:
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
if(gesture.state == UIGestureRecognizerStateEnded){
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];
[view release];
}
}
What you are doing wrong is releasing the object "view" too early, don't release it until the view is popped. That should fix the problem.
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];
Hey, I want to be able to check if user touches my UIView so I can dismiss my picker how can I do it actually? Thanks!
Try adding a UITapGestureRecognizer to your UIView class in the viewDidLoad of the UIViewController subclass that contains your UIView. It would look something like this:
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewTapped:)];
tap.numberOfTapsRequired = 1;
[self.aView addGestureRecognizer:tap];
[tap release];
}
Then implement a handler for the tap which, based on the above code, would look like this:
-(void)viewTapped:(UITapGestureRecognizer *)recognizer {
//Add in your picker dismissal code here
}
Hope this helps,
Justin