UIButton not respond in UIView - objective-c

UIButton in my view does not respond when I click it. Some one figure
out what I am doing wrong? Here is my entire code:
MyView.h
#interface Myview : UIView
#end
MyView.m
#import "MyView.h"
- (init){
self = [super init];
if(self)
[self createButton];
return self;
}
- (void) createButton{
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100,100,100,50)];
[button setTitle:#"Go" forState:UIControlStateNormal];
[button addTarget:self
`action:#selector(goAction)
forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
- (void) goAction{
NSString *test = #"Some text";
}
MyViewController.m
- (id) init{
self = [super init];
if (self) {
MyView *myview = [[MyView alloc] init];
[self.view addSubview:myview];
}
return self;
}`
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
ViewController.m
#import "ViewController.h"
#import "MyViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
MyViewController *myTestView = [[MyViewController alloc] init];
[self.view addSubview:myTestView.view];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end

The reason why clicks does not work is that you don't set frame of MyView
This way it works (although I still don't understand why you need to add one ViewController into another)
#implementation MyViewController
- (instancetype)init
{
self = [super init];
if (self) {
MyView *myview = [[MyView alloc] init];
myview.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width);
[self.view addSubview:myview];
}
return self;
}

Related

Add UITapGestureRecognizer to UIVIew XIB

#interface MyCustomView() #end
#implementation MyCustomView
- (instancetype)init {
self = [[[MyClass bundle] loadNibNamed:kOverlayNib owner:self options:nil] firstObject];
self.layer.cornerRadius = 10;
self.translatesAutoresizingMaskIntoConstraints = NO;
self.userInteractionEnabled = YES;
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[singleFingerTap setNumberOfTapsRequired:1];
[singleFingerTap setNumberOfTouchesRequired:1];
[self addGestureRecognizer:singleFingerTap];
return self; }
//The event handling method
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
NSLog(#"Tappedddddddddd");
}
I have added Tap Gesture Recognizer to my kOverlayNib.xib but for some reason i can not get any response.. It is not working at all..
you missed some things..
#interface MyCustomView() <UIGestureRecognizerDelegate> #end or anywhere you want to write.
singleFingerTap.delegate = self;
- (BOOL)gestureRecognizer:(UIGestureRecognizer )gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer)otherGestureRecognizer { return YES; }
Now you can run your code. it works.

Using a block in Object-C, I get "Thread 1:EXC_BAD_ACCESS(code=1,address=0x0)"

I want to add GestureRecognizer on an imageView and use a block in the clickAction.
But when I run it, I get this error in the block:
Thread 1:EXC_BAD_ACCESS(code=1,address=0x0)
#import "blockImage.h"
#implementation blockImage
-(instancetype)init{
if (self = [super init]) {
self = [[blockImage alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
self.tag = 10;
self.backgroundColor = [UIColor redColor];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tapActionWithBolck:)];
[self addGestureRecognizer:tap];
}
return self;
}
-(void)tapActionWithBolck:(void(^)(NSInteger idx))completion{
completion(10);
}
#end
and
#import "ViewController.h"
#import "blockImage.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
blockImage *img = [[blockImage alloc] init];
[self.view addSubview:img];
}
#end
You can not use method like this with UITapGestureRecognizer
-(void)tapActionWithBolck:(void(^)(NSInteger idx))completion;
it should be like that
-(void)tapAction:(UIGestureRecognizer *)sender;
or
-(void)tapAction;
If you want to use block on tap, you should keep it in variable (in init for example) and than call it in method. But keep in mind about retain cycles.

single uiview for many viewcontrollers

I have a viewcontroller name it as viewcontroller1. I have dragged a uiview to this viewcontroller and added some buttons to that view with actions. And also a custom view class is created for that uiview. This uiview is acting as a top bar for viewcontroller1. I have some more viewcontrollers and I am using the same uiview for those viewcontrollers too by getting the uiview using viewwithtag method. But the delegates are not working when I am using this method. I am getting a thread1 exc_bad access when the delegates are called from the uiview class. Any help is appreciated.
This is my uiview class
//topview.h
#protocol buttonprotocol <NSObject>
-(void) button1pressed;
-(void) button2pressed;
#end
#import <UIKit/UIKit.h>
#interface topview : UIView
- (IBAction)button1action:(id)sender;
- (IBAction)button2action:(id)sender;
#property (nonatomic,assign) id <buttonprotocol> delegate;
#property (weak, nonatomic) IBOutlet UIButton *button1;
#property (weak, nonatomic) IBOutlet UIButton *button2;
#end
//topview.m
#import "topview.h"
#implementation topview
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
- (IBAction)button1action:(id)sender
{
[self.delegate button1pressed];
}
- (IBAction)button2action:(id)sender
{
[self.delegate button2pressed];
}
#end
The given below is the first viewcontroller
// ViewController.h
#import <UIKit/UIKit.h>
#import "topview.h"
#import "button1ViewController.h"
#import "button2ViewController.h"
#interface ViewController : UIViewController
<buttonprotocol>
#property (weak, nonatomic) IBOutlet topview *topviewobj;
#end
// ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_topviewobj.delegate=self;
UIView *newview=[[UIView alloc]initWithFrame:CGRectMake(0, 250, 320, 100)];
newview=[self.view viewWithTag:1];
[self.view addSubview:newview];
// Do any additional setup after loading the view, typically from a nib.
}
-(void) button1pressed
{
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
button1ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"button1ViewController"];
[self presentViewController:vc animated:NO completion:nil];
}
-(void) button2pressed
{
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
button2ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"button2ViewController"];
[self presentViewController:vc animated:NO completion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
the given below is the view controller class for the viewcontroller when the first button is tapped.
// button1ViewController.h
#import <UIKit/UIKit.h>
#import "topview.h"
#import "ViewController.h"
#import "button2ViewController.h"
#class topview;
#interface button1ViewController : UIViewController
<buttonprotocol>
{
UIView *newview;
topview *topviewobj;
}
#end
// button1ViewController.m
#import "button1ViewController.h"
#interface button1ViewController ()
#end
#implementation button1ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
topviewobj=[topview new];
topviewobj.delegate=self;
NSLog(#"%#",topviewobj.delegate);
self.view.backgroundColor=[UIColor purpleColor];
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
newview=[[UIView alloc]init];
newview=[vc.view viewWithTag:1];
UIButton *backbutton=[[UIButton alloc]init];
[backbutton setTitle:#"Back" forState:UIControlStateNormal];
[backbutton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[backbutton setFrame:CGRectMake(5, 30, 60, 30)];
[backbutton addTarget:self action:#selector(back) forControlEvents:UIControlEventTouchUpInside];
[newview addSubview:backbutton];
[self.view addSubview:newview];
// Do any additional setup after loading the view.
}
-(void) back
{
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
[self presentViewController:vc animated:NO completion:nil];
}
-(void) button1pressed
{
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
button1ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"button1ViewController"];
[self presentViewController:vc animated:NO completion:nil];
}
-(void) button2pressed
{
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
button2ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"button2ViewController"];
[self presentViewController:vc animated:NO completion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Given below is the class for viewcontroller for the viewcontroller when second button is tapped.
// button2ViewController.h
#import <UIKit/UIKit.h>
#import "topview.h"
#import "ViewController.h"
#class topview;
#interface button2ViewController : UIViewController
<buttonprotocol>
{
UIView *newview;
topview *topviewobj;
}
#end
// button2ViewController.m
#import "button2ViewController.h"
#interface button2ViewController ()
#end
#implementation button2ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
topviewobj=[topview new];
topviewobj.delegate=self;
NSLog(#"%#",topviewobj.delegate);
self.view.backgroundColor=[UIColor purpleColor];
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
newview=[[UIView alloc]init];
newview=[vc.view viewWithTag:1];
UIButton *backbutton=[[UIButton alloc]init];
[backbutton setTitle:#"Back" forState:UIControlStateNormal];
[backbutton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[backbutton setFrame:CGRectMake(5, 30, 60, 30)];
[backbutton addTarget:self action:#selector(back) forControlEvents:UIControlEventTouchUpInside];
[newview addSubview:backbutton];
[self.view addSubview:newview];
// Do any additional setup after loading the view.
}
-(void) back
{
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
[self presentViewController:vc animated:NO completion:nil];
}
-(void) button1pressed
{
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
button1ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"button1ViewController"];
[self presentViewController:vc animated:NO completion:nil];
}
-(void) button2pressed
{
// UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
// button2ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"button2ViewController"];
// [self presentViewController:vc animated:NO completion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This is all I got. I can't show my original code due to privacy concerns. This is a sample created to show the issue. I can't upload images as I have low reputation.
This looks highly suspect...
UIView *newview=[[UIView alloc]initWithFrame:CGRectMake(0, 250, 320, 100)];
newview=[self.view viewWithTag:1];
[self.view addSubview:newview];
You shouldn't have to alloc init a new view if the next line you are going to use viewWithTag because that view would already be inited. Also in the next line you call addSubView on the same thing you just got the view which would only work if the view was already added.
Edit
After further inspection of your code I see what you are trying to do. There are a couple of things to note. If you want to pass an object to a new view controller you can do that when you create the new view controller.
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
button1ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"button1ViewController"];
//if button1ViewController had a property for topviewobj instead of an instance variable.
button1ViewController.topviewobj = (topview *)[self.view viewWithTag:1];
[self presentViewController:vc animated:NO completion:nil];
//in button1ViewController viewDidLoad
self.topviewobj.delegate = self;
[self.view addSubView:self.topviewobj];
With that being said I think what you really want to do is look into nibs or create topview just in code.
If just in code it would be something like
_topviewobj = [[topview alloc]initWithFrame:CGRectMake(0,250, 320, 100)];
_topviewobj.delegate = self;
[self.view addSubview:_topviewobj];
Also this will likely cause issues in the future...
-(void) back
{
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
[self presentViewController:vc animated:NO completion:nil];
}
Creating new UIViewControllers over and over again isn't ideal. Try this...
-(void) back
{
[self dismissViewControllerAnimated:YES completion:nil];
}
As I said before I would look into nibs or just creating a UIView Subclass and alloc/init, set delegate, and add as subview when you need one.
I hope all that makes sense and helps.

Cocoa Idiomatic First Responder and Keyboard Event Handling Design

I've been reading the Cocoa Event Handling Guide to understand how to handle keyboard events for my application. However, I'm not quite sure if the solution I've found is the idiomatic way to approach this problem or even the best.
I have a view called CustomView and controller called CustomViewController that contains a NSTextView (within a NSScrollView) and a NSTextField. Basically a chat window.
What I would like is that even if the NSTextField is not selected, and the user starts typing, the NSTextField should be made the first responder and the text the user types should be appended to the NSTextField.
I've come up with a solution (below) where my RootWindowController captures keyDown events, makes the NSTextField the first responder, gets the field editor, and appends the text.
Is this the idiomatic approach Cocoa developers take or is their a simpler way that I am missing? Code is below. Thanks.
RootWindowController.m
#import "RootWindowController.h"
#implementation RootWindowController
- (id)initWithWindow:(NSWindow *)window
{
self = [super initWithWindow:window];
if (self) {
self.customViewController = [[CustomViewController alloc] init];
NSView *contentView = self.window.contentView;
CGFloat viewWidth = contentView.frame.size.width;
CGFloat viewHeight = contentView.frame.size.height;
self.customViewController.customView.textField.frame =
NSMakeRect(0, 0, viewWidth, 50);
self.customViewController.customView.scrollView.frame =
NSMakeRect(0, 51, viewWidth, viewHeight - 50);
self.customViewController.customView.textView.frame =
NSMakeRect(0, 51, viewWidth, viewHeight - 50);
self.window.contentView = self.customViewController.customView;
}
return self;
}
- (void)keyDown:(NSEvent *)theEvent
{
[self.window
makeFirstResponder:self.customViewController.customView.textField];
NSString *characters = theEvent.characters;
NSText *fieldEditor = [self.window fieldEditor:YES
forObject:self.customViewController.customView.textField];
[fieldEditor setString:
[NSString stringWithFormat:#"%#%#", fieldEditor.string, characters]];
[fieldEditor setSelectedRange:NSMakeRange(fieldEditor.string.length, 0)];
[fieldEditor setNeedsDisplay:YES];
}
#end
CustomViewController.m
#import "CustomViewController.h"
#implementation CustomViewController
- (id)init
{
self = [super init];
if (self) {
self.customView = [[CustomView alloc] initWithFrame:NSZeroRect];
[self.customView setAutoresizesSubviews:YES];
self.view = self.customView;
}
return self;
}
#end
CustomView.m
#import "CustomView.h"
#implementation CustomView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect];
self.textView = [[NSTextView alloc] initWithFrame:NSZeroRect];
self.textField = [[NSTextField alloc] initWithFrame:NSZeroRect];
[self.textView setAutoresizesSubviews:YES];
[self.scrollView setDocumentView:self.textView];
[self.scrollView setHasVerticalScroller:YES];
[self.scrollView setAutoresizesSubviews:YES];
[self.textField setStringValue:#"Placeholder Text"];
[self addSubview:self.scrollView];
[self addSubview:self.textField];
[self.textView setNeedsDisplay:YES];
}
return self;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
#end

Subclass of UIView. How to add through Interface Builder?

I have a subclass of UITextField and want to be able to add it to the view in IB. What I did is added UITextField and changed its class to my subclass in Identity tab of Inspector. But I can only see UITextField on the view.
Code:
#interface ExtendedTextField : UITextField {
}
//implementation
#implementation ExtendedTextField
- (void)baseInit
{
UIImage * curImage = [UIImage imageNamed:#"tfbg.png"];
[self baseInitWithImage : curImage];
}
- (void)baseInitWithImage : (UIImage *) aImage
{
aImage = [aImage stretchableImageWithLeftCapWidth:29 topCapHeight:29];
self.background = aImage;
self.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
UIView * curLeftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, self.frame.size.height)];
self.leftView = curLeftView;
self.rightView = curLeftView;
[curLeftView release];
self.leftViewMode = UITextFieldViewModeAlways;
self.rightViewMode = UITextFieldViewModeAlways;
[self setTextColor:[UIColor greenColor]];
}
- (void)awakeFromNib
{
[super awakeFromNib];
[self baseInit];
}
/*
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self baseInit];
}
return self;
}
*/
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self)
{
[self baseInit];
}
return self;
}
- (id)initWithFrame:(CGRect)frame withImage:(UIImage*)aImage
{
self = [super initWithFrame:frame];
if (self) {
[self baseInitWithImage : aImage];
}
return self;
}
- (void)dealloc {
[super dealloc];
}
#end
EDIT: I noticed several things:
-- if I put [super initWithFrame:...] instead of [super initWithCoder:...] inside
(id)initWithCoder:(NSCoder *)aDecoder
it works well.
-- Now I am using awakefromnib instead of initwithcoder and the only thing that get changed in textfield is textColor.
Could someone explain why so?
Solution I needed to set border style to none. BS overlayed bg image.
While showing your .xib in Xcode, reveal the right pane, select your view and in the third tab, change Classto whatever you want it to be.