UIButton and UIViewContoller IOS7 - objective-c

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

Related

Remove subview and send control back

I am invoking "HelpviewController" from UIViewController using following code, which is working fine.
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"InnerHelpPageViewController"];
self.pageViewController.dataSource = self;
InnerHelpViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
// Change the size of page view controller
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 30);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
Inside my new controller InnerHelpViewController I have done button which should remove this newly added view and send control back to initiated page.
- (IBAction)unwindToMenuFromInnerHelp:(id)sender {
[self.view removeFromSuperview];
}
This call removing the newly added view, but the problem is "MenuController" is frozen. I couldn't do any clicks on it. Any help?
To explain flow--> I have menu screen where one button with name "help" --> When user clicks on this help button first snippet of code in this question executes and shows HelpViewController-->Once done with help, user clicks "Done" button--> Which should close the HelpViewController and move to "menu" screen.
Implement protocol method in InnerHelpViewController.h file class
#protocol InnerHelpViewControllerDelegate
-(void)removeCustomView;
#end
#interface InnerHelpViewController : UIViewController{
}
#property(nonatomic, weak) id<InnerHelpViewControllerDelegate> delegate.
In InnerHelpViewController.m file
#synthesize delegate;
- (IBAction)unwindToMenuFromInnerHelp:(id)sender {
[delegate removeCustomView];
}
in MenuController .h file Adopt InnerHelpViewControllerDelegate.
#interface MenuController : UIViewController<InnerHelpViewControllerDelegate>{
}
Now Confirm your delegate in MenuController.m file while helpviewcontroller object creation.
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"InnerHelpPageViewController"];
self.pageViewController.dataSource = self;
InnerHelpViewController *startingViewController = [self viewControllerAtIndex:0];
startingViewController.delegate = self;
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
// Change the size of page view controller
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 30);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
//Implement here delegate method
-(void)removeCustomView{
[self.pageViewController removeFromSuperview]
}

Mirror text from UITextField on inputAccessoryView - UIToolBar to text on UITextField on navigationController.toolbar

In my app I have a UITextField on the navigationController toolbar.
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic,strong) NSArray *toolBarButtonItems;
#property (nonatomic,strong) UITextField *textField;
#property (nonatomic,strong) UITextField *textField2;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.textField = [[UITextField alloc]initWithFrame:CGRectMake(0, 0, 60, 40)];
self.textField.delegate = self;
self.textField.borderStyle = UITextBorderStyleRoundedRect;
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.textField];
self.toolBarButtonItems = #[flexibleSpace,barButtonItem,flexibleSpace];
self.toolbarItems = self.toolBarButtonItems;
self.navigationController.toolbar.barTintColor = [UIColor blueColor];
[self.navigationController setToolbarHidden:NO animated:NO];
}
When the textField is clicked the keyboard opens up and I create a new inputAccessoryView toolbar with another textField.
-(UIToolbar *)addToolBar{
UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:self.navigationController.toolbar.frame];
toolbar.barTintColor = [UIColor darkGrayColor];
self.textField2 = [[UITextField alloc]initWithFrame:CGRectMake(0, 0, 60, 40)];
self.textField2.delegate = self;
self.textField2.borderStyle = UITextBorderStyleRoundedRect;
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.textField2];
[toolbar setItems:#[flexibleSpace,barButtonItem,flexibleSpace]];
return toolbar;
}
The idea is to change the firstResponder to the textField on the inputAccessoryView so this way I can see what I'm editing. The reason I am doing this is cause I can't scroll the Navigation toolbar up past the keyboard and I want to see the text that I am editing.
-(void)textFieldDidBeginEditing:(UITextField *)textField{
textField.inputAccessoryView = [self addToolBar];
if(self.textField2.isFirstResponder != NO){
[self.textField2 becomeFirstResponder];
}
}
It doesn't seem to be working when I click on the textField in the navigationController toolbar. The new inputAccessoryView toolbar shows up over the keyboard but I can't edit the field because the responder doesn't seem to be changing. The return key doesn't work either. I have to hit it twice in order to close the keyboard and when I do the text doesn't match up between the two text fields.
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
self.textField.text = self.textField2.text;
return YES;
}
I got it to work like this:
#import "KJMViewController.h"
#interface KJMViewController ()
#property (strong, nonatomic) UITextField *textField1;
#property (strong, nonatomic) UITextField *textField2;
#end
#implementation KJMViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.textField1 = [[UITextField alloc]initWithFrame:CGRectMake(30, 7, 260, 30)];
self.textField1.borderStyle = UITextBorderStyleRoundedRect;
self.textField1.delegate = self;
UIToolbar *navToolbar = self.navigationController.toolbar;
[navToolbar addSubview:self.textField1];
UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 44)];
self.textField2 = [[UITextField alloc]initWithFrame:CGRectMake(30, 7, 260, 30)];
self.textField2.borderStyle = UITextBorderStyleRoundedRect;
self.textField2.delegate = self;
[toolbar addSubview:self.textField2];
self.textField1.inputAccessoryView = toolbar;
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(firstRes:) name:UIKeyboardDidShowNotification object:nil];
}
- (void)firstRes:(id)sender
{
[self.textField2 becomeFirstResponder];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == self.textField2) {
self.textField1.text = self.textField2.text;
}
[textField resignFirstResponder];
[self.textField1 resignFirstResponder];
return YES;
}
- (void)viewDidDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter]removeObserver:self forKeyPath:UIKeyboardDidShowNotification];
[super viewDidDisappear:animated];
}
#end
Here's what's happening in viewDidLoad:
Initialise toolbar and textField2
Set the inputAccessory for textField1 (the one hidden by the keyboard) here so it's ready to become firstResponder
Then in the viewDidAppear method:
Sign up for a notification that's sent when the keyboard is shown. You'll then write some code in the "firstRes" method to make textField2 the firstResponder. You need to make it the firstResponder using this notification because you know that it's in the view hierarchy by this time, which means it's able to become firstResponder. Calling it in the -(void)textFieldDidBeginEditing:(UITextField *)textField seems to fire it before textField2 comes on screen, meaning that it can't become firstResponder. We sign up for it in the viewDidAppear method because we only want to get the notification if we're on screen.
After textField2 resignsFirstResponder, textField1 becomes first responder again, so you have to call resignFirstResponder twice in the textFieldShouldReturn method.
Also, if we leave the screen, we need to remove ourself as an observer of the keyboard notification in the viewDidDisappear method.
Here's a link to the project I made in Xcode so you can see how it works:
https://github.com/kylejm/UIToolBar-UITextView

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.

Dismiss keyboard from UISearchBar when adding as a subview

I wanted to add a UISearchBar to my view controller without storyboard so I added it programmatically as a subview. I have set the delegate and yet I can't seem to dismiss the keyboard by clicking on the search button.
here's my code:
#interface ViewController : UIViewController <UISearchBarDelegate>
{
IBOutlet UISearchBar* mySearchBar;
}
----
- (void)viewDidLoad
{
[mySearchBar setDelegate: self];
mySearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, self.navigationController.navigationBar.frame.origin.y, 320, 44)];
[self.view addSubview:mySearchBar];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)mySearchBar
{
[mySearchBar resignFirstResponder];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)mySearchBar
{
[mySearchBar resignFirstResponder];
}
You are setting the delegate before allocating the search bar. Try to set delegate afterwards.
mySearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, self.navigationController.navigationBar.frame.origin.y, 320, 44)];
[mySearchBar setDelegate: self];
It is always helpful to check whether the delegate methods are called in the first place. Set a break point and see :)

Trying to fix subview flipping and now subview buttons no longer work?

I have a view which includes two subviews. I had it working so that only one subview was shown at a time and each subview had a button and when the button was clicked the subview would flip over and the next subview would appear. The problem was that it appeared as though the entire view was flipping. After reading on this site about how to solve the problem I attempted to add the subviews to a container and flip that instead. However now, although my first subview is showing up when I press the button it no longer flip. It doesn't do anything. I put a log statement in the method which flips the subviews, as well as a breakpoint and as far as I can tell it no longer gets called. I'm very new to xcode and objective c and delegates and I have no idea how to proceed. Any help would be appreciated. Thanks.
I have included the relevant code here:
The header for the ViewController
#interface ExerciseViewController : UIViewController<ExerciseSubViewDelegate>
//stuff for subviews
#property (nonatomic, strong) ExerciseSubViewImage *subViewImage;
#property (nonatomic, strong) ExerciseSubViewText *subViewText;
#property UIView *panel;
#end
This is the code for the ViewController:
#interface ExerciseViewController ()
#end
#implementation ExerciseViewController
#synthesize subViewImage, subViewText;
- (void)viewDidLoad
{
self.subViewImage.delegate = self;
_panel = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.view.bounds.size.width, self.view.bounds.size.height/2)];
_panel.backgroundColor = [UIColor whiteColor];
[self.view addSubview:_panel];
[_panel addSubview:subViewImage];
}
-(ExerciseSubViewImage *)subViewImage
{
if (!subViewImage)
{
CGRect subViewImageFrame = CGRectMake(0,0, _panel.bounds.size.width, _panel.bounds.size.height);
self.subViewImage = [[ExerciseSubViewImage alloc] initWithFrame:subViewImageFrame];
[_panel addSubview:subViewImage];
}
return subViewImage;
}
-(ExerciseSubViewText *)subViewText
{
if (!subViewText)
{
CGRect subViewTextFrame = CGRectMake(0,0, _panel.bounds.size.width, _panel.bounds.size.height);
self.subViewText = [[ExerciseSubViewText alloc] initWithFrame:subViewTextFrame];
self.subViewText.backgroundColor = [UIColor blueColor];
[_panel addSubview:subViewText];
}
return subViewText;
}
-(void)exerciseSubViewImagePressed
{
[UIView transitionWithView:_panel
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[subViewImage removeFromSuperview];
[_panel addSubview:subViewText];
}
completion: nil];
//This is how I did it before I added the container
/*[UIView transitionFromView:subViewImage
toView:subViewText
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromRight
completion:nil];
self.subViewText.delegate = self;*/
NSLog(#"Ipushedtheimage");
}
-(void)exerciseSubViewTextPressed
{//I haven't updated this yet
[UIView transitionFromView:subViewText
toView:subViewImage
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromRight
completion:nil];
self.subViewImage.delegate = self;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
subViewImage = nil;
subViewText = nil;
}
#end
This is the code for the delegate
#import
#protocol ExerciseSubViewDelegate <NSObject>
-(void) exerciseSubViewImagePressed;
-(void) exerciseSubViewTextPressed;
#end
I am also added the code for the first subview:
#import
#import "ExerciseSubViewDelegate.h"
#interface ExerciseSubViewImage : UIView
#property (nonatomic, strong) UIButton *button;
#property (nonatomic, assign) id<ExerciseSubViewDelegate>delegate;
#property (strong, nonatomic) UIImageView *exerciseImageView;
#end
#import "ExerciseSubViewImage.h"
#import "UIImage+animatedGIF.h"
#implementation ExerciseSubViewImage
#synthesize button;
#synthesize delegate;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//Initialization code
self.button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
CGRect buttonFrame = CGRectMake(50,200,100,35);
self.button.frame = buttonFrame;
[self.button setTitle:#"Image"forState:UIControlStateNormal];
[self.button addTarget:self
action:#selector(buttonTouched)
forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.button];
_exerciseImageView = [[UIImageView alloc] initWithFrame:CGRectMake(50,20,160,158)];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"AppleLogo" withExtension:#"gif"];
_exerciseImageView.image = [UIImage animatedImageWithAnimatedGIFURL:url];
[self addSubview:self.exerciseImageView];
}
return self;
}
-(void)buttonTouched
{
NSLog(#"imagebuttonpressed");
[self.delegate exerciseSubViewImagePressed];
}
Again, any help would be appreciate. I know I'm probably just not understanding something simple.
Ok. This took me all weekend but I finally figured it out on my own. I thought I would shere the answer here in case anyone else ever has a similar problem. After trying several other approaches I finally went back to the approach I used here and started inserting a whole bunch of NSLogs to determine the order that every thing was executing in. What I finally ended up doing was changing this: (all in the top ViewController)
self.subViewImage.delegate = self;
_panel = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.view.bounds.size.width, self.view.bounds.size.height/2)];
_panel.backgroundColor = [UIColor whiteColor];
[self.view addSubview:_panel];
[_panel addSubview:subViewImage];
to this:
//create panel
_panel = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.view.bounds.size.width, s self.view.bounds.size.height/2)];
_panel.backgroundColor = [UIColor whiteColor];
[self.view addSubview:_panel];
[_panel addSubview:subViewImage];
//Set the subview delegates
self.subViewImage.delegate = self;
self.subViewText.delegate = self;